<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Drunk on Monads RSS Feed]]></title><description><![CDATA[Explore insightful and practical guides on software development and industry best practices. Join me for engaging and informative content tailored for you!]]></description><link>http://www.drunkonmonads.com</link><generator>GatsbyJS</generator><lastBuildDate>Tue, 04 Feb 2025 19:50:12 GMT</lastBuildDate><item><title><![CDATA[Useful Azure DevOps Boards queries]]></title><description><![CDATA[Photo by Stephen Dawson on Unsplash Useful Azure DevOps Boards Queries A collection of some useful Azure DevOps Boards queries. Grooming…]]></description><link>http://www.drunkonmonads.com/azure-boards-queries/</link><guid isPermaLink="false">http://www.drunkonmonads.com/azure-boards-queries/</guid><pubDate>Sat, 28 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@dawson2406?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Stephen Dawson&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/turned-on-monitoring-screen-qwtCeJ5cLYs?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Useful Azure DevOps Boards Queries&lt;/h1&gt;
&lt;p&gt;A collection of some useful Azure DevOps Boards queries.&lt;/p&gt;
&lt;h1&gt;Grooming queries&lt;/h1&gt;
&lt;p&gt;You will likely want to update the filters on these query to suite your needs, for example by filtering on specific work item types, state etc. What is saved and shown here are just the barebone queries.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View unparented items&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1536px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2559f5b739686d92cbf30f284afd0e59/e8464/1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 11.200000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAS0lEQVR42m3LwRGAMAhE0dQTIEAAE+2/MFePjjN7evCb61hVmbGOclNmEqaMOYRN9RHq8uJn8Jbh17lNR0yvDCgyDDcg+t8SD0L9BkIhFbVtDgxPAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;1&quot;
        title=&quot;&quot;
        src=&quot;/static/2559f5b739686d92cbf30f284afd0e59/e8464/1.png&quot;
        srcset=&quot;/static/2559f5b739686d92cbf30f284afd0e59/0eb09/1.png 500w,
/static/2559f5b739686d92cbf30f284afd0e59/1263b/1.png 1000w,
/static/2559f5b739686d92cbf30f284afd0e59/e8464/1.png 1536w&quot;
        sizes=&quot;(max-width: 1536px) 100vw, 1536px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View bugs parented under user stories/epics&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;⚠️This is a violation of the expected Epic -&gt; Feature -&gt; User story/Bug -&gt; Task hierarchy&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1523px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/26702d475db0b84a4c4d68b1d9b8cf90/15058/2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 37.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAwElEQVR42o2RWQ7DIAwFOUubjb2As/7l/pfqNEitukQqmlgPAvYzqHWZIXoHRg9D31mjbzEgYvBoPfRnqG2ZS06jFFIkDnmXU4Tg/SgZgfoJO1U9QxpKESleYxVP/Q371SRlGkVyInrv8ElWjCCkZJHinGX1J2pbl3R4K+nhGlEjMC9HA6e2qWmMpmbftc31wvekgfeVD9S+77TtrO4YbfMPr8MxhIcznikWYy2PY41hfnRluQR+1ba5BfCWYWqKOzTEUSd0SKHwAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;2&quot;
        title=&quot;&quot;
        src=&quot;/static/26702d475db0b84a4c4d68b1d9b8cf90/15058/2.png&quot;
        srcset=&quot;/static/26702d475db0b84a4c4d68b1d9b8cf90/0eb09/2.png 500w,
/static/26702d475db0b84a4c4d68b1d9b8cf90/1263b/2.png 1000w,
/static/26702d475db0b84a4c4d68b1d9b8cf90/15058/2.png 1523w&quot;
        sizes=&quot;(max-width: 1523px) 100vw, 1523px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View all work items in the current iteration&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1537px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b8c638cf19baf70efc0680aaa74712a4/29936/3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 13.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAW0lEQVR42m2NWw7AIAgEPU6rBVF5GNv0/scq+tmYTCZkWUJQYeHGXE04IyBcblNx10Km6smV4pYwunmp1fLcww9SPL2Na8hEOl7ifgBtCd2UMq6H0z9gGny15QPp+yDw+FQHywAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;3&quot;
        title=&quot;&quot;
        src=&quot;/static/b8c638cf19baf70efc0680aaa74712a4/29936/3.png&quot;
        srcset=&quot;/static/b8c638cf19baf70efc0680aaa74712a4/0eb09/3.png 500w,
/static/b8c638cf19baf70efc0680aaa74712a4/1263b/3.png 1000w,
/static/b8c638cf19baf70efc0680aaa74712a4/29936/3.png 1537w&quot;
        sizes=&quot;(max-width: 1537px) 100vw, 1537px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
You can also time travel across multiple iteration by adding &lt;code class=&quot;language-text&quot;&gt;+/- count&lt;/code&gt; in front of the &lt;code class=&quot;language-text&quot;&gt;@CurrentIteration&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View active work that is not assigned to the sprint&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This would likely indicate some previous work that has not been updated or has potentially fallen through the cracks.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1515px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/6bbb1d354268e6b4c1c30c731a0e07b4/970c6/4.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 15%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAcUlEQVR42j2NCw7DMAhDc5s1CZ9AGuim3f9ccxep0hPCYHBh6uf0jDXdcp02RIXQf64cynklVkNFmEBv9QGiuPH3ne6GM/jgaPVQYcMF04xY+G0DEoN6vB7wqsAcgUCFYCLqdxWiLTFFwr+/2fkb6u0H8xogrVMCncQAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;4&quot;
        title=&quot;&quot;
        src=&quot;/static/6bbb1d354268e6b4c1c30c731a0e07b4/970c6/4.png&quot;
        srcset=&quot;/static/6bbb1d354268e6b4c1c30c731a0e07b4/0eb09/4.png 500w,
/static/6bbb1d354268e6b4c1c30c731a0e07b4/1263b/4.png 1000w,
/static/6bbb1d354268e6b4c1c30c731a0e07b4/970c6/4.png 1515w&quot;
        sizes=&quot;(max-width: 1515px) 100vw, 1515px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View work items logged in the last x day&lt;/strong&gt;s&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1537px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/74d4ad9ad5e0370a22debb40b871579e/29936/5.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 12.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAATklEQVR42mWL2QnAIBAFbSe693pVYWL/zWTBn0BgeAwPJu3nVqZWvbrN0RByYMLCSAhz9BAo1/m/MGHae7mKqQrT6BEXKPlsxG56/A8hvIAxFk+btqNgAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;5&quot;
        title=&quot;&quot;
        src=&quot;/static/74d4ad9ad5e0370a22debb40b871579e/29936/5.png&quot;
        srcset=&quot;/static/74d4ad9ad5e0370a22debb40b871579e/0eb09/5.png 500w,
/static/74d4ad9ad5e0370a22debb40b871579e/1263b/5.png 1000w,
/static/74d4ad9ad5e0370a22debb40b871579e/29936/5.png 1537w&quot;
        sizes=&quot;(max-width: 1537px) 100vw, 1537px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View ill defined work items&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The default looks at items with no descriptions, or not acceptance criteria or no story points.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1511px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0d17337ca23c2ce2793dd2054e498779/7a5cc/6.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 18%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAgElEQVR42nWPSw7DIAxEOU2DMRgMDZC0SZr7X6rTROqiH+ktLMvzNDYlq6bUa82axmsJniV40OqoKQIMKcq5/MBst3l/bDhCrLdaciY7OCJkoPPMqlAIlt+Yfbmv6xIlsKOpt3nqGBxZJOGG0Q4X8Dvc2quwHG2hOPrwGXu/8I8nEOwrTLihlYoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;6&quot;
        title=&quot;&quot;
        src=&quot;/static/0d17337ca23c2ce2793dd2054e498779/7a5cc/6.png&quot;
        srcset=&quot;/static/0d17337ca23c2ce2793dd2054e498779/0eb09/6.png 500w,
/static/0d17337ca23c2ce2793dd2054e498779/1263b/6.png 1000w,
/static/0d17337ca23c2ce2793dd2054e498779/7a5cc/6.png 1511w&quot;
        sizes=&quot;(max-width: 1511px) 100vw, 1511px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View work items pending review&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1533px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/623a584f013f0b078872982fa2de2bd4/fa857/7.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 12%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAASElEQVR42m2LbQqAMAxDd521XT/WTsX7H8zg/okQEvLgNddxrKqc6FUpTMgMYHFTEKa+4SdDuGXofZ3hBsFggDK923EBf80tPzOsFWbry6AAAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;7&quot;
        title=&quot;&quot;
        src=&quot;/static/623a584f013f0b078872982fa2de2bd4/fa857/7.png&quot;
        srcset=&quot;/static/623a584f013f0b078872982fa2de2bd4/0eb09/7.png 500w,
/static/623a584f013f0b078872982fa2de2bd4/1263b/7.png 1000w,
/static/623a584f013f0b078872982fa2de2bd4/fa857/7.png 1533w&quot;
        sizes=&quot;(max-width: 1533px) 100vw, 1533px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View unestimated work items&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1532px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9d579b725df972372596f6d3bde95401/b5cb9/8.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 14.399999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAYklEQVR42mWNWQ6AIAwFuY3SgkBZ3O5/L+eLGE2mUCav1PVmo7dWrbcag6r4nDaeNGN0Kzmo/CHJ6e5jr2aE7uvcYvDrkrhUxK9IfqFHUh/Q7thHyYk4CxljcIKEt5mQVPEPn70gDw0zCIcAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;8&quot;
        title=&quot;&quot;
        src=&quot;/static/9d579b725df972372596f6d3bde95401/b5cb9/8.png&quot;
        srcset=&quot;/static/9d579b725df972372596f6d3bde95401/0eb09/8.png 500w,
/static/9d579b725df972372596f6d3bde95401/1263b/8.png 1000w,
/static/9d579b725df972372596f6d3bde95401/b5cb9/8.png 1532w&quot;
        sizes=&quot;(max-width: 1532px) 100vw, 1532px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View blocked work items&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1532px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/52cfa9f5944fe26f9399cb1aff6e2e23/b5cb9/9.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 14.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAYUlEQVR42nWMSw6AMAgFvY2FQj9CuzFa738qX11qTN4CJplZrBZ3c9uaW3dT4ciEu5ZccurN8Urk11Qi+DKO/RpnVmlPgmllCjCTxJwUkMIkr8GcMtpbLSglle/+OLpM4Qa4IiA5FqElwAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;9&quot;
        title=&quot;&quot;
        src=&quot;/static/52cfa9f5944fe26f9399cb1aff6e2e23/b5cb9/9.png&quot;
        srcset=&quot;/static/52cfa9f5944fe26f9399cb1aff6e2e23/0eb09/9.png 500w,
/static/52cfa9f5944fe26f9399cb1aff6e2e23/1263b/9.png 1000w,
/static/52cfa9f5944fe26f9399cb1aff6e2e23/b5cb9/9.png 1532w&quot;
        sizes=&quot;(max-width: 1532px) 100vw, 1532px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View work items that may need to be broken down&lt;/strong&gt;
This is determined by high estimates and you can decide on the threshold.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1534px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/125361d1ee9b1c0a0e3131bdf1e28c12/68141/10.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 12%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAASUlEQVR42nWLSw7AIAgFvU5FPgKC3v9ipemyaTKLycubJoS53E1j+c7AAYXpJBzC7GYD+jt+aSp0MoRJp+x44npXCf1ixJKyP25ENxWUwjf9IAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;10&quot;
        title=&quot;&quot;
        src=&quot;/static/125361d1ee9b1c0a0e3131bdf1e28c12/68141/10.png&quot;
        srcset=&quot;/static/125361d1ee9b1c0a0e3131bdf1e28c12/0eb09/10.png 500w,
/static/125361d1ee9b1c0a0e3131bdf1e28c12/1263b/10.png 1000w,
/static/125361d1ee9b1c0a0e3131bdf1e28c12/68141/10.png 1534w&quot;
        sizes=&quot;(max-width: 1534px) 100vw, 1534px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View stale work items&lt;/strong&gt;
You can decide on the time period for this to be considered stale.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1505px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c5d647fda70b6b036ed3b0ea7fb4e91a/2ae13/11.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 17.400000000000002%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAfUlEQVR42j2OCw6DIBBEOYsRFZHPLuBq9XBQL95pSZo8wmSGnUW9W9XjcB5CMeTETNG7DewlwyEmkZL4awYcu9rVdKDV81SjR5EdSSmZOZplQpDQstnAdN8XSvuwWeZ50h1o1VrFdb1OZEzYTP1dDB6Cgs85eedQDX6fcn8+DjsjYUVotsEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;11&quot;
        title=&quot;&quot;
        src=&quot;/static/c5d647fda70b6b036ed3b0ea7fb4e91a/2ae13/11.png&quot;
        srcset=&quot;/static/c5d647fda70b6b036ed3b0ea7fb4e91a/0eb09/11.png 500w,
/static/c5d647fda70b6b036ed3b0ea7fb4e91a/1263b/11.png 1000w,
/static/c5d647fda70b6b036ed3b0ea7fb4e91a/2ae13/11.png 1505w&quot;
        sizes=&quot;(max-width: 1505px) 100vw, 1505px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View unassigned items in the current iteration&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1508px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/adb9d8536934631e2e24e1cb01ee379a/6068e/12.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 15.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAa0lEQVR42l2NCwqAMAxDdxl1a7u1+yqK97+WQUFEeJQ0NKmLwiVbbxWzlpKiwMlmozdo+NlUmJjCD5iuFj33rTVk9Th200TBQ5sluXtRG4X8MgU/f0Heqcq2DlzjIZL49oAVU1N8eP0XYboApukgNS9rT4kAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;12&quot;
        title=&quot;&quot;
        src=&quot;/static/adb9d8536934631e2e24e1cb01ee379a/6068e/12.png&quot;
        srcset=&quot;/static/adb9d8536934631e2e24e1cb01ee379a/0eb09/12.png 500w,
/static/adb9d8536934631e2e24e1cb01ee379a/1263b/12.png 1000w,
/static/adb9d8536934631e2e24e1cb01ee379a/6068e/12.png 1508w&quot;
        sizes=&quot;(max-width: 1508px) 100vw, 1508px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View work items that are due soon&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1530px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a44264a67dca7b309cc81bda9d7ab2e0/77e4e/13.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 12.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAVklEQVR42nWM2Q2AMAxDOw5N3ANSesD+e2HRz4JkOU+ObNdbPXKqxXKKAQoob6snmUkxgwr5U270lmO4r0FQv6l4llmbwJyT8uarnB373KavCsDfCyoPpSQf11H4okkAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;13&quot;
        title=&quot;&quot;
        src=&quot;/static/a44264a67dca7b309cc81bda9d7ab2e0/77e4e/13.png&quot;
        srcset=&quot;/static/a44264a67dca7b309cc81bda9d7ab2e0/0eb09/13.png 500w,
/static/a44264a67dca7b309cc81bda9d7ab2e0/1263b/13.png 1000w,
/static/a44264a67dca7b309cc81bda9d7ab2e0/77e4e/13.png 1530w&quot;
        sizes=&quot;(max-width: 1530px) 100vw, 1530px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View overdue work items&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1544px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/006a73b258ceb871818451896c548913/bb3e3/14.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 12.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAUUlEQVR42mPIz8vV19G2sDA3MzWxtrQw0NfT1dE2NjI0NNAHMi3MzYEkUAgTAcUZMjLSNNXV9HV1NTXUgdrUVFWASF1NDUyqAkU01NUggpgIAKheFcMbrf9tAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;14&quot;
        title=&quot;&quot;
        src=&quot;/static/006a73b258ceb871818451896c548913/bb3e3/14.png&quot;
        srcset=&quot;/static/006a73b258ceb871818451896c548913/0eb09/14.png 500w,
/static/006a73b258ceb871818451896c548913/1263b/14.png 1000w,
/static/006a73b258ceb871818451896c548913/bb3e3/14.png 1544w&quot;
        sizes=&quot;(max-width: 1544px) 100vw, 1544px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;Other queries&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;View items assigned to me&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1510px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2c846155a7cd9d6b3630fb381e7756f2/1d574/15.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 10.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAS0lEQVR42mWLSw6AMAhEex75tEChGnv/czkrF5o8JpMHtJqe4Stzul2rVJjpcBvhJkx736MrDPqfVhnnSlx3FQwS/wA7JPRrPgjTA1uWFgXY5auKAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;15&quot;
        title=&quot;&quot;
        src=&quot;/static/2c846155a7cd9d6b3630fb381e7756f2/1d574/15.png&quot;
        srcset=&quot;/static/2c846155a7cd9d6b3630fb381e7756f2/0eb09/15.png 500w,
/static/2c846155a7cd9d6b3630fb381e7756f2/1263b/15.png 1000w,
/static/2c846155a7cd9d6b3630fb381e7756f2/1d574/15.png 1510w&quot;
        sizes=&quot;(max-width: 1510px) 100vw, 1510px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View items that I am following&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1515px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/53c85250504c898025b88f20d406d5aa/970c6/16.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 11.200000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAARklEQVR42l2LAQrAMAgD+51p1Lajuv+/bIFBGYULJIe27nhyVa57jtFD5SIsnFCpynCjYT8wSAs+V/LaDczmm9Tk7zcGfQE2mhWwAQ78GQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;16&quot;
        title=&quot;&quot;
        src=&quot;/static/53c85250504c898025b88f20d406d5aa/970c6/16.png&quot;
        srcset=&quot;/static/53c85250504c898025b88f20d406d5aa/0eb09/16.png 500w,
/static/53c85250504c898025b88f20d406d5aa/1263b/16.png 1000w,
/static/53c85250504c898025b88f20d406d5aa/970c6/16.png 1515w&quot;
        sizes=&quot;(max-width: 1515px) 100vw, 1515px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;View items where I have recently been mentioned&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1517px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/94c55d442cae07e4e5ac85c59b68ea8f/e3807/17.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 11.200000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAATUlEQVR42l2NWw6AMAgEex1bkIeWCvc/mOtfYzIh7A4JzZRzRcS83FyFRmcabop4MuWzYt5YUO6MflRlU2F4U8HFDtM30cL8FMCPynwBVlQWGuvErzwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;17&quot;
        title=&quot;&quot;
        src=&quot;/static/94c55d442cae07e4e5ac85c59b68ea8f/e3807/17.png&quot;
        srcset=&quot;/static/94c55d442cae07e4e5ac85c59b68ea8f/0eb09/17.png 500w,
/static/94c55d442cae07e4e5ac85c59b68ea8f/1263b/17.png 1000w,
/static/94c55d442cae07e4e5ac85c59b68ea8f/e3807/17.png 1517w&quot;
        sizes=&quot;(max-width: 1517px) 100vw, 1517px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Instead of constantly querying the grooming type queries, you can &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/report/dashboards/add-charts-to-dashboard?view=azure-devops#add-a-work-item-query-or-chart&quot;&gt;assign them to a dashboard as charts &lt;/a&gt; or as tile widgets so you always have a good view.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1026px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c63cc7499481ad9825910f2da2db09a7/9cda9/18.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 71.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAIAAACgpqunAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACZElEQVR42nVSu09TURzuX+EijkbRwRhjQpwIk9HBxISBwahRExkYXRx0cXHUxJj4YGgQCiFgAxqNEB5NXJAEKKW0lJZXW9qCl3vveT/9nXvVBT3JfZzv/L7f78v3nQQllGLEKBac+yHChGiltNKYSy4VY4xKaaKljRHaWGulNko7JEEJCRDGoe/jUFq3tFYhQpxi/6Da8DxoLZUWQiBAw6DQOPT8QEkBbRLaWu7t2MHrfQP93ZmmNTAXMPuhUE8nH3WOZPo3jmALIFP61uxm29By5+T6DuIAJuChE318sq9J9fnhlWSxBUgNi9PDqwuVSrpYPzuSO2BO05t88+JoDjPe8630YH7rDzndy74+RspeGs32rzcB2UX8zHA2U/Ontg/bR1YbRAD4KtfoGF+z1tyfLd+dqzgySJc/t2yy62Hy3bWZfaN/y36db7WlVk4NrbwvtCIjQLa5OVU6MbB0OZ2vhJFsxMFmqlnY8j1nAligNOLSSlIL8D6JTbRYKMo5eFwOGJGuu3MbUQYesmgPZ1obqVSISYixjCTEqbjYuIhFxWWOzCiFGEx55svSQhG5IUDGhFnU2Psx9rG4yyI5UBxLgO/vv9iw7+VK7e3VZxPjJ0dLeyGFSgZRTY9vDd7pGFu6Pbcdz7fHliPf+Fx4vrgDIzvTay+W9wEpeqQ9lat6QaHpnUtlq1Gqx+mO/GSxdmEs/zJbbxtcnq+HLjylwdLeTOXe7OaViXUn2ZjjoxPG3Vj9dLHa9amQKh0ABLbAO++R7unNnunShs/+K9tnghBkhfMqPoeojihXNLBK/K3712D7C+0e7zk4wf63AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;18&quot;
        title=&quot;&quot;
        src=&quot;/static/c63cc7499481ad9825910f2da2db09a7/9cda9/18.png&quot;
        srcset=&quot;/static/c63cc7499481ad9825910f2da2db09a7/0eb09/18.png 500w,
/static/c63cc7499481ad9825910f2da2db09a7/1263b/18.png 1000w,
/static/c63cc7499481ad9825910f2da2db09a7/9cda9/18.png 1026w&quot;
        sizes=&quot;(max-width: 1026px) 100vw, 1026px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;💡 In addition to placing charts and other visualization on a dashboard, you can only place these on the query itself. For example you can create a &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/report/dashboards/configure-chart-work-items-widget?view=azure-devops&quot;&gt;pivot table&lt;/a&gt;) to visualize the data from the query.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 470px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f1f4ced272caf14a2ac3b9140c501de3/c52b7/19.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 103.19148936170212%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAVCAIAAADJt1n/AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAC1UlEQVR42o1T3VLTQBhNC4qOjjpeOSNJNpvd/GzSNGlp0p+x2AoFoaBisVosghQFLoDRR9FnwAt9C654Ay+cUS50vNB38KQVWioXzpzsfMl+Z8/5vv0icc6qlclabbpUzKc9d35+rhCFQojF+vzDhbmUK3SqcaafC8ngDBwfjyvwns0EXsqxbJErTwPCcTijyBkE0nqrxCjNR1G1ejeXzdRma1EUsa4UoVTTKGdsSI3p1HWEsC0EEtNjtampe2FuolKphGEIMjYMpOoUwSnnNICsafC/tiklqiJrWrzqhLi25VgmmJZtQYKBwFkc4CymO8I2OevXPAj4CQI/nfaQlPZSmcCHScD34y8Adr2U21fuHQOfGmPv7geHS97Rg9TrZk5qF6+sFK62S8DlduFaq8CEwTSN85OGnZJhRmP802Lwven8boi37Yy0defSTlnqFBKbxZHtcnItL+uqocdF9lrQJ6dTriHEQd3/3HC+LYm9lUDart7an5PWo5FO6ebebHI1khnBpcQWh8gADH1YCI6b7s+Gs/88K3WKIy/zWKWNAvSTL/IKI8r4bVVV+g0brBnkr033R8PZA3mzNNopgZzYKCZelWLbjFBVIYNk1rtPFKOzYeVY80R5La9wQmS5r8y7V+e6DsaYWdZBPfiy7Bw/cnZbcc3Xd6ZQc7JTurE7k1jNj+uqMEzMRb9m0zQs07BNgxrGR3T7qftr2XmzmpW2yhe3ytJm7Hl0ZzK5XoBtTBEh6j+247Fk72f8w0VxVLc7j31pJRxrhRdb4YVn4WgrHHsygYZpytmaB4c2LSyLyDZV8WvIVJWRqxOlGyuxqCKj24p8hmww1GvagGlomgYTyMBxmNZ47ImKuiCI2PNcnZ69Z6wYYHQOZOzhgYRhcIwxApAdxwYT/CDjD5NPbduQksdJ9zKRrQzEveAc2z3xHuKDqaZ3gRf9JB78cv4v+f/gTP8DEi3fwNHh9V4AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;19&quot;
        title=&quot;&quot;
        src=&quot;/static/f1f4ced272caf14a2ac3b9140c501de3/c52b7/19.png&quot;
        srcset=&quot;/static/f1f4ced272caf14a2ac3b9140c501de3/c52b7/19.png 470w&quot;
        sizes=&quot;(max-width: 470px) 100vw, 470px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;
Here are recommendations of some great things to visualize&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bug trends over time&lt;/li&gt;
&lt;li&gt;Task burn down&lt;/li&gt;
&lt;li&gt;Test case pass/fail rate&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Additional tips for working with queries&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Utilize the predefined variables like &lt;code class=&quot;language-text&quot;&gt;@Me&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;@Today&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;@CurrentIterations&lt;/code&gt; etc to your advantage.&lt;/li&gt;
&lt;li&gt;Use tags wisely. These can help filter work items, but if used without disciple they can go out of hand fast. As a general rule, if you have no use case to query by a given tag, you should not be using it. This will keep your tags list clean.&lt;/li&gt;
&lt;/ul&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[File Signature Checks in .NET]]></title><description><![CDATA[Photo by Jason Mavrommatis on Unsplash File Signature Checks in .NET If you have an application that receives an file uploads, it is best…]]></description><link>http://www.drunkonmonads.com/file-signature-checks/</link><guid isPermaLink="false">http://www.drunkonmonads.com/file-signature-checks/</guid><pubDate>Sat, 28 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jeisblack?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Jason Mavrommatis&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/green-metal-gate-with-brown-metal-padlock-8yYAaguVDgY?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;File Signature Checks in .NET&lt;/h1&gt;
&lt;p&gt;If you have an application that receives an file uploads, it is best practice to validate these files. It is common to see validation on extensions and mime types, although this is not fool proof and leaves lots of room for malicious files to be uploaded.&lt;/p&gt;
&lt;p&gt;A more solid way to validate binary files is to check the unique header that each file type has, know as the magic number, that can be used to identify the type. For example if allowing PDF, you can verify that the signature matches that of a PDF. Depending on the file type, some will have more than one potential file signature.&lt;/p&gt;
&lt;p&gt;In .NET &lt;a href=&quot;https://github.com/neilharvey/FileSignatures&quot;&gt;FileSignatures&lt;/a&gt; is a really good library for this and has a very simple API for identifying files. It covers a lot of files that you are most likely to encounter, like popular image and video formats, PDF, Excel/Word/PowerPoint/Open Office, Outlook messages, Zip files and more.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Having started off reinventing the wheel using public domain information to verify signatures, it proved a bit hard as a lot of the sources were not complete. For example the information on &lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_file_signatures&quot;&gt;Wikipedia&lt;/a&gt; states that a PDF will have the signature &lt;code class=&quot;language-text&quot;&gt;%PDF-&lt;/code&gt; or HEX &lt;code class=&quot;language-text&quot;&gt;25 50 44 46 2D&lt;/code&gt; which generally is correct as the first bytes will be &lt;code class=&quot;language-text&quot;&gt;%PDF-[version number]&lt;/code&gt;, except some PDF variants have no version and would just be &lt;code class=&quot;language-text&quot;&gt;%PDF&lt;/code&gt;. or HEX &lt;code class=&quot;language-text&quot;&gt;25 50 44 46&lt;/code&gt; This was one of many false negatives I was getting and on collating more information I came up with better checks, which happened to match what FileSignatures had when I stumbled upon it, giving confidence it was sufficiently battle tested. &lt;a href=&quot;https://github.com/Sicos1977/MSGReader/blob/master/MsgReaderCore/Helpers/FileTypeSelector.cs&quot;&gt;This&lt;/a&gt; was also a decent source of reliable signatures.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If you are not working with .NET taking a look at the implementation and seeing what signatures are used can be a great start to hand roll something your self.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Usage example&lt;/h2&gt;
&lt;p&gt;Think clean architecture and avoid the dependency leaking into your Domain and Use Cases by wrapping it in infrastructure.&lt;/p&gt;
&lt;p&gt;Example Port:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IFileFormat&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// Returns true if the file is a PDF by checking the file signature&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;stream&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;IsPdf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// Returns true if the file is an image by checking the file signature&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// GIF, BMP, JPEG, PNG, WEBP, TIFF&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;stream&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;IsImage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example Infra:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FileFormat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IFileFormat&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IFileFormatInspector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_fileFormatInspector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FileFormat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IFileFormatInspector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fileFormatInspector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_fileFormatInspector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fileFormatInspector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// Returns true if the file is a PDF by checking the file signature&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;stream&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;IsPdf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_fileFormatInspector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;DetermineFileFormat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Pdf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// Returns true if the file is an image by checking the file signature&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// GIF, BMP, JPEG, PNG, WEBP, TIFF&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;stream&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;IsImage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_fileFormatInspector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;DetermineFileFormat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Image&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FileSignatures&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// Registers the file signatures service.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;services&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IServiceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddFileSignatures&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IServiceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IFileFormatInspector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FileFormatInspector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddTransient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IFileFormat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FileFormat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Registration in host&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddFileSignatures&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Pro Tip&lt;/h3&gt;
&lt;p&gt;When working with File Signature checks you risk getting false negative for some file types as there may be so many variations in the wild. Do make sure to log any failures and include at least the first 10 bytes of that file, so that you do not have to follow up asking for files to be shared with you which can be annoying for user and at times hard do the sharing of sensitive information using insecure mediums.&lt;/p&gt;
&lt;p&gt;Example&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;override&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Handle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ValidateFileUploadRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BeginScope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;FileExtension&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fileExtension&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;ContentType&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ContentType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Header&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetFileHeader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// in case we get false negatives, we can investigate the file header and see if it&amp;#39;s a valid file&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;     &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;LogWarning&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Uploaded file failed all validation.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetFileHeader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ValidateFileUploadRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;byte&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[] &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fileHeader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BinaryReader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Text&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;leaveOpen&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// for investigation purposes, we read the first 10 bytes of the file and add to log context&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fileHeader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;reader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ReadBytes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;); &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// safe, returns fewer bytes if the end of the stream is reached&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Stream&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Join&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fileHeader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Select&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$&amp;quot;0x{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;X2&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk17 { color: #808080; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[OWASP ZAP API scan automation with Azure Pipelines]]></title><description><![CDATA[Photo by Scott Webb on Unsplash OWASP ZAP API scan automation with Azure Pipelines [[TOC]] OWASP ZAP) is a free, feature-filled web app…]]></description><link>http://www.drunkonmonads.com/owasp-zap-api-scan/</link><guid isPermaLink="false">http://www.drunkonmonads.com/owasp-zap-api-scan/</guid><pubDate>Sat, 28 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@scottwebb?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Scott Webb&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/two-bullet-surveillance-cameras-attached-on-wall-yekGLpc3vro?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;OWASP ZAP API scan automation with Azure Pipelines&lt;/h1&gt;
&lt;p&gt;[[&lt;em&gt;TOC&lt;/em&gt;]]&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.zaproxy.org/getting-started/&quot;&gt;OWASP ZAP&lt;/a&gt;) is a free, feature-filled web app scanner. Being under the OWASP banner, you can be sure that it is backed by a lot of industry experts and security best practices. This tool is particularly great for those who are new to security testing and have limited knowledge and skills, but would still like to ensure that their web apps are secure.&lt;/p&gt;
&lt;p&gt;You can make use of the desktop application, which is available for download &lt;a href=&quot;https://www.zaproxy.org/&quot;&gt;here&lt;/a&gt;). This article however goes over how to automate API scans using the docker images shipped by ZAP. Docker is the easiest way to get started with ZAP automation and offers a lot of flexibility, there are however &lt;a href=&quot;https://www.zaproxy.org/docs/automate/&quot;&gt;other ways to automate ZAP&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Short intro to ZAP&lt;/h2&gt;
&lt;p&gt;At its core, ZAP is what is known as a &lt;code class=&quot;language-text&quot;&gt;man-in-the-middle proxy.&lt;/code&gt; It stands between the tester’s browser and the web application so that it can intercept and inspect messages sent between the browser and web application, modify the contents if needed, and then forward those packets to the destination. It can be used as a stand-alone application and as a daemon process.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 525px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a9fd8d18c2986308433670c34fb9928a/635dd/1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 21.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAA8klEQVR42mO4++rr6jMvN55/tfHCqzVnX95//e3////vP3y4fvXShUtXInu2H7n97j8YXHr8afnJZ5suvNxw/uXyk8+fvPvOsPrMi7DplzIXX8tacs1/yoW1Z198+/Hrxfuv9TM3/P/1JbpplW75zm+//nz4/GPO4cc+ky6WrrpRtPKG54QLh2+/B2kOmnYxY/G1nKXX/SaDNH/99vP7n/9ahRuqpm7YuuugVt6ad19/f/n6c9GxJ9mLr1SsuQFESfMvHwFqBjob6Fo0ZwPBmtNPFXI2+VYvWbHtIETk5osv2y+/2nP1ze6rb7ZeevXi4w8AIfm6J1CcgXoAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;1&quot;
        title=&quot;&quot;
        src=&quot;/static/a9fd8d18c2986308433670c34fb9928a/635dd/1.png&quot;
        srcset=&quot;/static/a9fd8d18c2986308433670c34fb9928a/0eb09/1.png 500w,
/static/a9fd8d18c2986308433670c34fb9928a/635dd/1.png 525w&quot;
        sizes=&quot;(max-width: 525px) 100vw, 525px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;ZAP ships out multiple docker images that can be used for scanning web apps, of interest &lt;code class=&quot;language-text&quot;&gt;ghcr.io/zaproxy/zaproxy:stable&lt;/code&gt; which is used in this article.&lt;/p&gt;
&lt;p&gt;All of the docker images (apart from the ‘bare’ one) provide a set of packaged scan scripts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.zaproxy.org/docs/docker/baseline-scan/&quot;&gt;Baseline Scan&lt;/a&gt; which runs the ZAP spider against the target for (by default) 1 minute followed by an optional ajax spider scan before reporting the results of the passive scanning.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.zaproxy.org/docs/docker/full-scan/&quot;&gt;Full Scan&lt;/a&gt; which runs the ZAP spider against the target (by default with no time limit) followed by an optional Ajax spider scan and then a full active scan before reporting the results.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.zaproxy.org/docs/docker/api-scan/&quot;&gt;API Scan&lt;/a&gt; which performs an active scan against APIs defined by OpenAPI, or GraphQL (post 2.9.0) via either a local file or a URL. - This is the one we shall be working with&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;ZAP API scan&lt;/h2&gt;
&lt;p&gt;The ZAP API scan is a script that is available in the ZAP &lt;a href=&quot;https://www.zaproxy.org/docs/docker/about/&quot;&gt;Docker&lt;/a&gt; images. It is tuned for performing scans against APIs defined by OpenAPI, SOAP, or GraphQL via either a local file or a URL. It imports the definition that you specify and then runs an Active Scan against the URLs found. The Active Scan is tuned to APIs, so it doesn’t bother looking for things like XSSs.&lt;/p&gt;
&lt;p&gt;It also includes 2 scripts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Raise alerts for any HTTP Server Error response codes&lt;/li&gt;
&lt;li&gt;Raise alerts for any URLs that return content types that are not usually associated with APIs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For our example, we are going to run the container with this configuration&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;🖱️ Click to expand&lt;/summary&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Run a Docker container using the specified image&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;docker run \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Mount the current directory to /zap/wrk/ in the container with read/write access&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-v &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$(pwd)&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:/zap/wrk/:rw \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Allocate the container&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-t ghcr.io/zaproxy/zaproxy:stable zap-api-scan.py \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Target URL for the API scan, dynamically specifies the JSON file from Swagger&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-t &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;$(ZapApiTarget)/$(apiSuffix)/swagger.json&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Specify HTML report file name&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-r report.html \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Output in JSON format&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-j \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Ignore minor warnings&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-I \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Set the alert threshold level (minimum level to consider)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-l INFO \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Run all active scans&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-a \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Use specified config file for the scan&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-c api-scan.conf \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Use specified context file&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-n api.context \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Set the input format as OpenAPI&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-f openapi \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Set default level for additional rules&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;-i WARN&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;This will start the container to target a site URL we provide outputting an HTML report of the scan results.&lt;/p&gt;
&lt;p&gt;The configuration file provides the rules that should be used in the scan and the desired response. A default configuration file can be created using the ‘-g’ parameter&lt;/p&gt;
&lt;p&gt;We will make use of the following configuration&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;🖱️ Click to expand&lt;/summary&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# zap-api-scan rule configuration file&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Change WARN to IGNORE to ignore rule or FAIL to fail if rule matches&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Active scan rules set to IGNORE will not be run which will speed up the scan&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Only the rule identifiers are used - the names are just for info&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# You can add your own messages to each rule by appending them after a tab on each line.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;0	WARN	(Directory Browsing - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10003	WARN	(Vulnerable JS Library - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10009	WARN	(In Page Banner Information Leak - Passive/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10010	WARN	(Cookie No HttpOnly Flag - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10011	WARN	(Cookie Without Secure Flag - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10012	WARN	(Password Autocomplete &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Browser - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10015	WARN	(Re-examine Cache-control Directives - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10017	WARN	(Cross-Domain JavaScript Source File Inclusion - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10019	WARN	(Content-Type Header Missing - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10020	WARN	(Anti-clickjacking Header - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10021	WARN	(X-Content-Type-Options Header Missing - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10023	WARN	(Information Disclosure - Debug Error Messages - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10024	WARN	(Information Disclosure - Sensitive Information &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; URL - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10025	WARN	(Information Disclosure - Sensitive Information &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; HTTP Referrer Header - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10026	WARN	(HTTP Parameter Override - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10027	WARN	(Information Disclosure - Suspicious Comments - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10028	WARN	(Open Redirect - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10029	WARN	(Cookie Poisoning - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10030	WARN	(User Controllable Charset - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10031	WARN	(User Controllable HTML Element Attribute (Potential XSS) - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10032	WARN	(Viewstate - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10033	WARN	(Directory Browsing - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10034	WARN	(Heartbleed OpenSSL Vulnerability (Indicative) - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10035	WARN	(Strict-Transport-Security Header - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10036	WARN	(HTTP Server Response Header - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10037	WARN	(Server Leaks Information via &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;X-Powered-By&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; HTTP Response Header Field(s) - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10038	WARN	(Content Security Policy (CSP) Header Not Set - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10039	WARN	(X-Backend-Server Header Information Leak - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10040	WARN	(Secure Pages Include Mixed Content - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10041	WARN	(HTTP to HTTPS Insecure Transition &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Form Post - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10042	WARN	(HTTPS to HTTP Insecure Transition &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Form Post - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10043	WARN	(User Controllable JavaScript Event (XSS) - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10044	WARN	(Big Redirect Detected (Potential Sensitive Information Leak) - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10045	WARN	(Source Code Disclosure - /WEB-INF folder - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10048	WARN	(Remote Code Execution - Shell Shock - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10049	WARN	(Content Cacheability - Passive/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10050	WARN	(Retrieved from Cache - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10052	WARN	(X-ChromeLogger-Data (XCOLD) Header Information Leak - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10054	WARN	(Cookie without SameSite Attribute - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10055	WARN	(CSP - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10056	WARN	(X-Debug-Token Information Leak - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10057	WARN	(Username Hash Found - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10061	WARN	(X-AspNet-Version Response Header - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10062	WARN	(PII Disclosure - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10063	WARN	(Permissions Policy Header Not Set - Passive/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10094	WARN	(Base64 Disclosure - Passive/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10095	WARN	(Backup File Disclosure - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10096	WARN	(Timestamp Disclosure - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10097	WARN	(Hash Disclosure - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10098	WARN	(Cross-Domain Misconfiguration - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10099	WARN	(Source Code Disclosure - Passive/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10105	WARN	(Weak Authentication Method - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10108	WARN	(Reverse Tabnabbing - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10109	WARN	(Modern Web Application - Passive/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10110	WARN	(Dangerous JS Functions - Passive/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;10202	WARN	(Absence of Anti-CSRF Tokens - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;2	WARN	(Private IP Disclosure - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;20012	WARN	(Anti CSRF Tokens Scanner - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;20014	WARN	(HTTP Parameter Pollution scanner - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;20015	WARN	(Heartbleed OpenSSL Vulnerability - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;20016	WARN	(Cross-Domain Misconfiguration - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;20017	WARN	(Source Code Disclosure - CVE-2012-1823 - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;20018	WARN	(Remote Code Execution - CVE-2012-1823 - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;20019	WARN	(External Redirect - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;3	WARN	(Session ID &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; URL Rewrite - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;30001	WARN	(Buffer Overflow - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;30002	WARN	(Format String Error - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;30003	WARN	(Integer Overflow Error - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40003	WARN	(CRLF Injection - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40008	WARN	(Parameter Tampering - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40009	WARN	(Server Side Include - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40012	WARN	(Cross Site Scripting (Reflected) - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40013	WARN	(Session Fixation - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40014	WARN	(Cross Site Scripting (Persistent) - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40016	WARN	(Cross Site Scripting (Persistent) - Prime - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40017	WARN	(Cross Site Scripting (Persistent) - Spider - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40018	WARN	(SQL Injection - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40019	WARN	(SQL Injection - MySQL - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40020	WARN	(SQL Injection - Hypersonic SQL - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40021	WARN	(SQL Injection - Oracle - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40022	WARN	(SQL Injection - PostgreSQL - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40023	WARN	(Possible Username Enumeration - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40026	WARN	(Cross Site Scripting (DOM Based) - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40028	WARN	(ELMAH Information Leak - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;40032	WARN	(.htaccess Information Leak - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;42	WARN	(Source Code Disclosure - SVN - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;50000	WARN	(Script Active Scan Rules - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;50001	WARN	(Script Passive Scan Rules - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;6	WARN	(Path Traversal - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;7	WARN	(Remote File Inclusion - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90001	WARN	(Insecure JSF ViewState - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90002	WARN	(Java Serialization Object - Passive/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90003	WARN	(Sub Resource Integrity Attribute Missing - Passive/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90004	WARN	(Insufficient Site Isolation Against Spectre Vulnerability - Passive/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90011	WARN	(Charset Mismatch - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90019	WARN	(Server Side Code Injection - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90020	WARN	(Remote OS Command Injection - Active/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90022	WARN	(Application Error Disclosure - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90026	WARN	(SOAP Action Spoofing - Active/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90028	WARN	(Insecure HTTP Method - Active/beta)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90029	WARN	(SOAP XML Injection - Active/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90030	WARN	(WSDL File Detection - Passive/alpha)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;90033	WARN	(Loosely Scoped Cookie - Passive/release)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;The context file provides an additional configuration that indicates what URLs should be scanned and additional scan configuration. Consult the desktop documentation for instructions on how to save the context from a configuration done with the application.&lt;/p&gt;
&lt;p&gt;We shall be using the following context file&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;🖱️ Click to expand&lt;/summary&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; encoding&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;UTF-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; standalone&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;no&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Test API&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;desc&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;inscope&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;inscope&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;incregexes&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;https://c1sjmvgw-7023.uks1.devtunnels.ms/.*&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;incregexes&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;tech&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.CouchDB&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.Firebird&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.HypersonicSQL&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.IBM DB2&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.Microsoft Access&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.Microsoft SQL Server&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.MongoDB&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.MySQL&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.Oracle&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.PostgreSQL&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.SAP MaxDB&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.SQLite&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Db.Sybase&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Language&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Language.ASP&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Language.C&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Language.JSP/Servlet&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Language.Java&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Language.Java.Spring&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Language.JavaScript&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Language.PHP&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Language.Python&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Language.Ruby&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Language.XML&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;OS&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;OS.Linux&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;OS.MacOS&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;OS.Windows&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;SCM&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;SCM.Git&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;SCM.SVN&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;WS&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;WS.Apache&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;WS.IIS&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;WS.Tomcat&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;tech&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;urlparser&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;org.zaproxy.zap.model.StandardParameterParser&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;{&amp;quot;kvps&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;&amp;amp;amp;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;quot;,&amp;quot;kvs&amp;quot;:&amp;quot;=&amp;quot;,&amp;quot;struct&amp;quot;:[]}&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;urlparser&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;postparser&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;org.zaproxy.zap.model.StandardParameterParser&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;{&amp;quot;kvps&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;&amp;amp;amp;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;quot;,&amp;quot;kvs&amp;quot;:&amp;quot;=&amp;quot;,&amp;quot;struct&amp;quot;:[]}&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;postparser&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;authentication&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;EACH_RESP&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;pollfreq&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;pollfreq&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;pollunits&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;REQUESTS&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;pollunits&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;authentication&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;forceduser&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;-1&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;forceduser&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;session&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;authorization&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;basic&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;header&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;logic&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;AND&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;logic&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;-1&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;basic&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;authorization&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;For the actual scan we will be running we shall simply create a new ASP.NET Core Web API using the default Visual Studio template and tunnel this over the public internet from a development machine so our demonstration Azure Pipeline can access it without the need to deploy somewhere. The scan can be done against an OpenAPI, SOAP or GraphQL spec, in our case the Web API emits a Swagger OpenAPI spec that we will point to.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1610px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3889c9d8dbb3a4ff9d0dea714ecb9150/41396/2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABsklEQVR42o3QW2sTQRQH8PkmeTGtmETrQ5sWfAgqkqoPoqD4mYS2alsQCj74CcQXkaqgtVQLBRFp0qTJtt1k73PdnZnd2Yu70j52k8OP83T+Zw4DesennZ7W7Z90+2c9TRvBIylVNE0pBSIpQsGFEKEMszRL4lQpFceTqKLAQc/c/aMddgf9oW57xIE5Ws5FeScQU/BzwH4cYdujhkscEnhMlIO+NCEbnFkuZsAjfOQwLBIqUyKSaUA/srGgPAIOlRYWKIhhoGDRJ0M8RvkWroCLAwf5+RpfxkGYTOn/vAJjyA0khwYycWjRqEAmsGl0YlGXSmCT0CJSM9EYBmNUMLEol88bWHosBJ4fG4R39FMde07gW4yRKKVRVoKEqcMUClQRzi//8Onr+4+ft7/vfdn5VW77297O/u/zMBZZZzhutVrNhfla7Vq9XivRaDRmqlfay8uun5yHDwej+w8ePn/67NbS0nyzuXC55uLi3M25R4+fXIRl9vdYz19ut+/duF6vVqszl9fs7NVKpXL7zt2LMI91h26+2Vpb31x9vbHycr3E6quNFytrW2/f5T9FuPoHnSLNvNP9BR4AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;2&quot;
        title=&quot;&quot;
        src=&quot;/static/3889c9d8dbb3a4ff9d0dea714ecb9150/41396/2.png&quot;
        srcset=&quot;/static/3889c9d8dbb3a4ff9d0dea714ecb9150/0eb09/2.png 500w,
/static/3889c9d8dbb3a4ff9d0dea714ecb9150/1263b/2.png 1000w,
/static/3889c9d8dbb3a4ff9d0dea714ecb9150/41396/2.png 1610w&quot;
        sizes=&quot;(max-width: 1610px) 100vw, 1610px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The most important being the incregexes which indicates the URL &lt;a href=&quot;https://c1sjmvgw-7023.uks1.devtunnels.ms/&quot;&gt;https://c1sjmvgw-7023.uks1.devtunnels.ms/&lt;/a&gt;.* This URL will be what we will tunnel our sample API via for scanning over the public internet.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ This is for demonstration purposes and to eventually allow Azure Pipelines to access an API that is on a local development machine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;On running this we will be able to see any scan issues in the console. For example, we may see something like this&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;WARN-NEW: Cookie No HttpOnly Flag [10010] x 2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	https://c1sjmvgw-7023.uks1.devtunnels.ms/WeatherForecast (200 OK)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;	***/v1/swagger.json (200 OK)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can find full usage instructions &lt;a href=&quot;https://www.zaproxy.org/docs/docker/api-scan/&quot;&gt;here&lt;/a&gt;).&lt;/p&gt;
&lt;h2&gt;Azure Pipelines&lt;/h2&gt;
&lt;p&gt;We can then proceed to use the same approach we have seen above, in an Azure Pipeline.&lt;/p&gt;
&lt;details&gt;
&lt;summary&gt;🖱️ Click to expand&lt;/summary&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;yml&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$(Year:yyyy).$(Month)$(rev:.r)-owasp-zap&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;none&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;defaultLevelForAdditionalRules&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Default rules not in the config file to&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;WARN&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;PASS&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;IGNORE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;INFO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;WARN&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;FAIL&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;minimumLevel&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Minimum level to show in report&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;INFO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;PASS&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;IGNORE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;INFO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;WARN&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;FAIL&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Group Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;project&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;[Project Name]&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# decide on a schedule or trigger for the scan&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# schedules:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;#     - cron: &amp;quot;0 0 1 * *&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;#       displayName: First day of each month midnight&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;#       branches:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;#           include:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;#               - master&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;stages&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;apiScan&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Run OWASP ZAP - API Scan&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;apiScanJob&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;matrix&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;v1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;apiSuffix&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;v1&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# v2:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;#   apiSuffix: &amp;#39;v2&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;API Scan&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;CopyFiles@2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SourceFolder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;zap-config&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Contents&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;**&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;TargetFolder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;./&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;OverWrite&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bash&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              chmod -R 777 ./&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              docker run \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -v $(pwd):/zap/wrk/:rw \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -t ghcr.io/zaproxy/zaproxy:stable zap-api-scan.py \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -t &amp;#39;$(ZapApiTarget)/$(apiSuffix)/swagger.json&amp;#39; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -r report.html \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -j \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -I \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -l ${{parameters.minimumLevel}} \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -a \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -c api-scan.conf \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -n api.context \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -f openapi \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;              -i ${{parameters.defaultLevelForAdditionalRules}}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Trigger docker scan&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# when working with API keys&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# -e ZAP_AUTH_HEADER_VALUE=&amp;#39;$(ZAP_AUTH_HEADER_VALUE)&amp;#39; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# -e ZAP_AUTH_HEADER=&amp;#39;$(ZAP_AUTH_HEADER)&amp;#39; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;PublishPipelineArtifact@1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Publish Report&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;succeeded()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;targetPath&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;report.html&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;artifactName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;artifact-zap-api-scan-report&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Bash@3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;targetType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;inline&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                cat report.html | tr -d &amp;#39;\n&amp;#39; | jq --arg to &amp;quot;$(ZapRunRecipients)&amp;quot; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                                                    --arg from &amp;quot;$(ZapSenderEmail)&amp;quot; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                                                    --slurp --raw-input \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                                                    &amp;#39;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                  personalizations: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                      to: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                          email: $to&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                      ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                  ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                  from: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                    email: $from&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                  subject: &amp;quot;OWASP ZAP - API Scan Report&amp;quot;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                  content: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                      type: &amp;quot;text/html&amp;quot;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                      value: .&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                  ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                }&amp;#39; &amp;gt; payload.json&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                curl --request POST \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                  --url https://api.sendgrid.com/v3/mail/send \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                  --header &amp;#39;Authorization: Bearer $(SendGridApiKey)&amp;#39; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                  --header &amp;#39;Content-Type: application/json&amp;#39; \&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;                  --data-binary &amp;quot;@payload.json&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/details&gt;
&lt;p&gt;This pipeline makes use of Send Grid via curl to send the report as an email. You can edit this step to your requirements. The report file is also available as a published artefact after the pipeline run.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1530px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ccc774a28fbb0b080e1a69df29ed10b2/77e4e/3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 29.400000000000006%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAA2UlEQVR42m2OCW6DMBBFfZGwJSyBYIwZ24BtEpI0VSrR+x+nP0VqkVrpaeb7z2ZmtB6H3tnBO/vC21Y0QDS84TXirxYv3fCTou7xdjdasdt1/lyW98e9N6o3GlYnW9mKcRyu82XyjkgORs/nyVCHknXe+wn30MOcHT+eT6zQShmj1muI+JGzlmSLW0jLebpQB1+RIiL01KeKfccSIG+BC7Z6ff4IjDApRXkssvTwL+lhfyzyqiohOK+LPNtWWV5m2BRHURgEfwl2uySOMQOdZ+k+SeCspSgMvwCfDEGKT7NWSQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;3&quot;
        title=&quot;&quot;
        src=&quot;/static/ccc774a28fbb0b080e1a69df29ed10b2/77e4e/3.png&quot;
        srcset=&quot;/static/ccc774a28fbb0b080e1a69df29ed10b2/0eb09/3.png 500w,
/static/ccc774a28fbb0b080e1a69df29ed10b2/1263b/3.png 1000w,
/static/ccc774a28fbb0b080e1a69df29ed10b2/77e4e/3.png 1530w&quot;
        sizes=&quot;(max-width: 1530px) 100vw, 1530px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1511px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a8403074b8257b560dc9fca372984936/7a5cc/4.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 16.599999999999998%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAS0lEQVR42pWMSQqAQAwE8xKzjFnnoPj/x5mjjiehSEOaLjjOy8yYUJiG8C9AVeesDK/wfQjh1qKF9lZm39efETp6W5VtWusH4f5tb71uGA2SGBjuAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;4&quot;
        title=&quot;&quot;
        src=&quot;/static/a8403074b8257b560dc9fca372984936/7a5cc/4.png&quot;
        srcset=&quot;/static/a8403074b8257b560dc9fca372984936/0eb09/4.png 500w,
/static/a8403074b8257b560dc9fca372984936/1263b/4.png 1000w,
/static/a8403074b8257b560dc9fca372984936/7a5cc/4.png 1511w&quot;
        sizes=&quot;(max-width: 1511px) 100vw, 1511px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1307px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a041936e28b222e2049b171ed1b45dfc/2da83/5.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 73.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAChUlEQVR42m2S227TQBCGLUR7U6q2qG0KKuohTuzYjZN4vV47ieMkPtvxIWfSFO4qEBdU3PEiFZVQhXgGruF5eAFA4iaMnRYE5ZN2NdLO7M4//1KFjGKxSNP0MmAYBhZN50kn8ILQdRzbtj3Pi6IoDMNKpQKZpQzKMIzBYDAcDmezGewQJhnj8TjpDyfT6WQyOT09nc/nsC9z4IpqtcqyLDXOiOPEshy4qNloIlECMMaiWKveUskQBKFWq4miyPN8+rLSbCotTZQJz4nlE6nKS0ggPFM+PDrMZ4AW5g43bb9IRhfj2Zvp/LnhzTt2z3Ed1+33+9BOEAQglRDyO/sfqEs5/77w4JrbvOY2rkqbPVVSmlpb10GClgF9grz/F1eCl4ed8010toWfPcTzstSQUA1JkqIooA3Eg07I4+6QFnMddNQQ9jDzSGYfy2yeLaZGMQy8tpQH3oGJ+TwYWQT9y0GAW+m0h1Him45v2Y7RdQ0zjmLXdS3Lsm8xTdP3fXAI/HYcB9wcjUa9Xg86oiJ7MA3PRsHMt0Nd17WW1voDxF1Ne6Lr9zxvW9MoTeM7HQvGAWflcpny9MhvJ04r8NpRt2k3iCah1GExBbSfHByc7+1dCcLl9vYVw4QYC4SoMEWwmorNyciZh8bAbfeIrMiYYAlLGQgRRWF3dj5ubCxk+efKyuL4+EJVOULqcJoWu3qYmJO+9dTvxGI6ZyTdgpBMSCmXe7e+/p3nv66u/qDpV6rKy7J6U+y1w8gcxuYo6CZaXcc4/ZhLMr9Ku7sf1tYWLPvt/v0FTb+u13l4GU7TYqPp2pqvKW0Fqwi0/gVCqLS//zaX+1ypfNra+lIoTKEKYwK/neO4X04aznJFog8cAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;5&quot;
        title=&quot;&quot;
        src=&quot;/static/a041936e28b222e2049b171ed1b45dfc/2da83/5.png&quot;
        srcset=&quot;/static/a041936e28b222e2049b171ed1b45dfc/0eb09/5.png 500w,
/static/a041936e28b222e2049b171ed1b45dfc/1263b/5.png 1000w,
/static/a041936e28b222e2049b171ed1b45dfc/2da83/5.png 1307w&quot;
        sizes=&quot;(max-width: 1307px) 100vw, 1307px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1663px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b55767f2891a60be5d20f98923a73618/28611/6.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 37.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAA7klEQVR42n2Qy07EMAxF+yUIdpQVeU2aJq7zqpvpMGKDgP//Etx2w2Z6dSI7sW+UuNP6RalnIZ7Wq//9Xpmfr9YWu5Ah0rUK71+973e2BIB5C6F3ru+CR6UuTMXW0ifhfYl3wo+CDUJyzls7Xi6O4eQf3hjbEc1SCqVkmHypqdSca3KjFfL9OFcPxNUOAI5NCnWJN8KV8JbD7AfQp5JSdqUUDmyOmOZKNc8lVTeMRpvj0jNzjPHoGP0IEyBOGHlNwy5r7ZmZO7TS27OxLPlKpc1pqZFyLACBdWbmsP9egkOtzDagDS2FFLseDUwI8Qfd12mBaxhTIwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;6&quot;
        title=&quot;&quot;
        src=&quot;/static/b55767f2891a60be5d20f98923a73618/28611/6.png&quot;
        srcset=&quot;/static/b55767f2891a60be5d20f98923a73618/0eb09/6.png 500w,
/static/b55767f2891a60be5d20f98923a73618/1263b/6.png 1000w,
/static/b55767f2891a60be5d20f98923a73618/28611/6.png 1663w&quot;
        sizes=&quot;(max-width: 1663px) 100vw, 1663px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This article barely scratches the surface on what you can do with OWASP ZAP. A good starting point would be to play with the desktop application and go through the documentation to see what ZAP can do and automate that. It will mostly be about exporting your configuration so you can consume it in the docker containers.&lt;/p&gt;
&lt;p&gt;This article specifically covered API scanning, but you can use it to scan any web app, including running aggressive attacks to see how resilient the penetration measures are.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;🛑&lt;strong&gt;Think twice&lt;/strong&gt; before considering running OWASP ZAP on an application in a production environment as you can cause real damage.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;🛑 &lt;strong&gt;NEVER&lt;/strong&gt; run OWASP ZAP against a site that you do not own without authorization as that can constitute hacking and is unethical.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; keep the ethos of Playwright in mind. The tool is simple and does two things and two things well, perform actions and assert state against expectations. Unlike a lot of other traditional tools, having to wait for things prior to actions or asserts &lt;strong&gt;is not a thing&lt;/strong&gt; and when done is usually a smell of something else being wrong.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These design choices allow Playwright users to forget about flaky timeouts and racy checks in their tests altogether.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; familiarize yourself with useful commands&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests headless&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests in debug mode&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --debug&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests with parallelization disabled&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --workers=1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run tests with fail-fast&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --max-failures=10&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests with tracing on&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# this should always be used on CI runs&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --trace on&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run a specific test by file name&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [test-file-name].ts&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run a specific test by test title&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -g [target title]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run tests that contain certain string in the file name&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [target-string] &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# target strings can be chained&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run specific tests by  directory&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; test/[directory-name] &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# directories can be chanined&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests in headed mode&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --headed&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests in a specific browser&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --project webkit &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# --project can be chained&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# view last run test report&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright show-report&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all test with the UI&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --ui&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run the code gen to generate tests off a browser interaction&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright codegen [optional-url]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# get help 🆘&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --help&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; familiarize yourself with the Playwright &lt;a href=&quot;https://playwright.dev/docs/trace-viewer-intro&quot;&gt;tracing and trace viewer.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; familiarize yourself with the various test &lt;a href=&quot;https://playwright.dev/docs/test-annotations&quot;&gt;annotations&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider targeting the &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;latest LTS node version&lt;/a&gt; at the point of creating a new Playwright project. This ensures that you start of with the latest guaranteed support with the widest compatibility and stability.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Consider using &lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;NVM&lt;/a&gt; or an alternative, to manage your node versions especially if you are likely to work on multiple things that may end up having different node version requirements.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright&quot;&gt;official Playwright VS Code extension&lt;/a&gt; for an improved experience.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The VS Code test runner runs your tests on the default browser of Chrome. To run on other/multiple browsers click the play button’s dropdown and choose another profile or modify the default profile by clicking &lt;code class=&quot;language-text&quot;&gt;Select Default Profile&lt;/code&gt; and select the browsers you wish to run your tests on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; keep your playwright and related dependencies up to date. By updating regularly you keep up with the new features, continued improvements in browser support, bug fixes, compatibility with new features etc. Incrementally updating tends to be much easier than a big bang when you finally need a specific version, especially when dealing with breaking changes.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npm install -D @playwright/test@latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Also download new browser binaries and their dependencies:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright install --with-deps&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# check the version&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright --version&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Consider &lt;a href=&quot;https://docs.npmjs.com/cli/v10/commands/npm-outdated/&quot;&gt;npm-outdated&lt;/a&gt; as a tool to manage your dependencies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Consider using the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=pflannery.vscode-versionlens&quot;&gt;Version Lens extension in VS Code&lt;/a&gt; to check for outdated packages and update them on the click of a button.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the page object model approach to separate the management of a single page’s logic into one source of truth for a clean code structure that encourages the single responsibility making the maintenance of a large test suite over time easier.&lt;/p&gt;
&lt;p&gt;This generally makes your tests easier to read at the top level, example:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;given valid details, creating a new credit application from scratch should succeed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BusinessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerificationPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BusinessVerificationPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documentsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DocumentsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetails&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BusinessDetailsBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerification&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BusinessVerificationBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DocumentsBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// submit business details&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;goto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;assertInitialState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetails&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// submit business verification details&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerificationPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;assertInitialState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerificationPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerification&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerificationPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;submitManualUpload&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// upload documents&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documentsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;assertInitialState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documentsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documentsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A page object model class is generally just a class that accepts a page (or more) and encapsulates any logic about that page like locators, assertions, actions etc. Here is a sample skeleton&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SamplePage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;doneButton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;doneButton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getByRole&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;button&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Done&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;assertInitialState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;goto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;goto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;doneButton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; adopt fakers for creating random yet realistic test data. For TypeScript tests, the library &lt;a href=&quot;https://fakerjs.dev/&quot;&gt;Faker JS&lt;/a&gt; is an excellent choice for this.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; adopt a builder model to separate the creation of test data from everything as with one source of truth that allows for a test suite to remain maintainable. Sample:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;LandLordBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;LandLord&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;LandLord&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;override&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;faker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cellphoneNumber&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`0&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;faker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;numeric&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;emailAddress&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;faker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;internet&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;leaseStartDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;faker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;past&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;leaseEndDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;faker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;future&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;# &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Example&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;usage&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;landlord&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;LandLordBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example relies on the following base implementation.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;10&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;withBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;withMany&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ignoreProperty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;abstract&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;implements&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: { [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } = {};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;typeConstructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extractPropertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;withBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extractPropertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;withMany&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extractPropertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;abstract&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ignoreProperty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extractPropertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;createInstance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;createInstance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;typeConstructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extractPropertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;([^&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Couldn&amp;#39;t extract property name.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DynamicBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;typeCtor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;typeCtor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Method not implemented.&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt;  consider configuring a base URL for your tests so this can be defined in one place and reused across your tests.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;11&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;defineConfig&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;baseURL:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;http://127.0.0.1:3000&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt;  consider reading any application configuration, regardless of source (environment variables, key vault secrets etc), in a central run once fixture.&lt;/p&gt;
&lt;p&gt;Example. This will pull values from a .env file using &lt;a href=&quot;https://www.npmjs.com/package/dotenv&quot;&gt;dotenv&lt;/a&gt; and pull user secrets from an &lt;a href=&quot;https://azure.microsoft.com/en-gb/products/key-vault&quot;&gt;Azure Key Vault&lt;/a&gt; using a getSecret utility method.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;12&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@playwright/test&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotenv&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;process&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;getSecret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;../helpers/secrets&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ConfigurationFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ConfigurationFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({}, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;secrets&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;userPassword:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getSecret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;user-password&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;imitateEmailAuth:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getSecret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;websocket-auth&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;userEmail:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;UserEmail&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;secrets&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;getSecret utility&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;13&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@azure/identity&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;SecretClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@azure/keyvault-secrets&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;credential&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;vaultName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;[vault name]&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`https://&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;vaultName&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;.vault.azure.net`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SecretClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;credential&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt; * Retrieves a secret from Azure Key Vault based on the given secret name.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt; * &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; The name of the secret to retrieve.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt; * &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@returns&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; The value of the secret as a string.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt; * &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@throws&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; Will throw an error if unable to retrieve the secret.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt; */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getSecret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;secret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getSecret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;secret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; write tests that assert the visible behaviour of your application and not on the inner workings. This will make your tests more resilient to changes in the underlying implementation. Examples of good things to check&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Elements on the page and their state i.e. what is visible, what is enabled etc.&lt;/li&gt;
&lt;li&gt;The URL of the page&lt;/li&gt;
&lt;li&gt;The title of the page&lt;/li&gt;
&lt;li&gt;A screenshot of the page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Examples of things that may be less resilient to changes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The exact structure of the DOM&lt;/li&gt;
&lt;li&gt;The CSS classes used on elements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; critically think through and configure the desired browsers and devices to run your tests on. This will ensure that your tests are running on the platforms that are most important to you and will help you catch issues early.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;14&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;defineConfig&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;projects:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;chromium&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Desktop Chrome&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;firefox&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Desktop Firefox&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;webkit&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Desktop Safari&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    } &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/* Test against mobile viewports. */&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Mobile Chrome&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Pixel 5&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Mobile Safari&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;iPhone 12&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    } &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/* Test against branded browsers. */&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Microsoft Edge&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Desktop Edge&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;], &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;channel:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;msedge&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Google Chrome&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Desktop Chrome&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;], &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;channel:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;chrome&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; fast track your process by leveraging the &lt;a href=&quot;https://playwright.dev/docs/codegen-intro&quot;&gt;Playwright test generator&lt;/a&gt; to create tests for you. This will give you a good starting point and you can then modify the tests to suit your needs.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;15&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright codegen [optional-url]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;You can also generate tests using &lt;a href=&quot;https://playwright.dev/docs/test-use-options&quot;&gt;emulation&lt;/a&gt; to generate a test for a specific viewport, device, color scheme, as well as emulate the geolocation, language or timezone.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; enable retries on CI to make your tests more resilient to flakiness.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; enable tracing to help diagnose failing tests in CI.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Traces and debugging can also be leveraged locally to diagnose issues with your tests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of test hooks (&lt;code class=&quot;language-text&quot;&gt;test.describe&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;test.beforeEach&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;test.afterEach&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;test.beforeAll&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;test.afterAll&lt;/code&gt;) for grouping and granular tests to make sure each test is specific and focused. This will make it easier to diagnose failures and will make your tests more resilient to changes in the application.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; keep up with the [Playwright release notes](&lt;a href=&quot;https://playwright.dev/docs/release-notes&quot;&gt;Release notes | Playwright&lt;/a&gt;) as a nice way to see what new APIs are being released.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; setup linting for your playwright tests with the [ESLint plugin for Playwright.](&lt;a href=&quot;https://www.npmjs.com/package/eslint-plugin-playwright&quot;&gt;eslint-plugin-playwright - npm (npmjs.com)&lt;/a&gt;). Enable caching with your linting for faster subsequent runs.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;16&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npm init @eslint/config@latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sample .eslintrc.json config&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;17&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;parser&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;@typescript-eslint/parser&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;parserOptions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;ecmaVersion&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;sourceType&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;module&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;plugins&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;@typescript-eslint&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;extends&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;eslint:recommended&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;plugin:@typescript-eslint/recommended&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;plugin:playwright/recommended&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;rules&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {},&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;env&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;browser&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;es2021&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;18&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;# in package.json&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;scripts&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;lint&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;eslint &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;**/*.ts&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; --cache&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;lint-staged&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;*.ts&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;eslint --cache&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider &lt;a href=&quot;https://github.com/lint-staged/lint-staged&quot;&gt;lint staged&lt;/a&gt; as a way to be able to run linting only for the files that you have just changed. &lt;code class=&quot;language-text&quot;&gt;npm install -D lint-staged&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;19&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;# in package.json&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;lint-staged&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;*.ts&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;eslint --cache&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⚠️ &lt;strong&gt;DO&lt;/strong&gt; give close attention to the need for any waits or sleeps in your tests. This is a common source of flakiness and should in most cases not be necessary given how Playwright is designed to work.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Playwright assertions are designed in a way that they describe the expectations that need to be eventually met.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Playwright automatically waits for the wide range of actionability checks to pass before performing each action.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of an .env file to have a single source of truth for environment values. You can conveniently load env files globally by adding this into your &lt;code class=&quot;language-text&quot;&gt;playwright.config.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;20&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;defineConfig&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@playwright/test&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotenv&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Read from default &amp;quot;.env&amp;quot; file.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; write custom assertions to simplify assertions you use in combination or common things you assert that require custom logic.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;21&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@playwright/test&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;baseExpect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@playwright/test&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;baseExpect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toBeVisibleAndEmpty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assertionName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;toBeVisibleAndEmpty&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;isVisible&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;isVisible&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;isVisible&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`expected locator to be visible`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pass:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;textContent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;isEmpty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() === &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;isEmpty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`expected locator to be empty, but got &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pass:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`locator is visible and empty`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pass:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assertionName&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO&lt;/strong&gt; not hard code secrets in tests or any artifact that will be committed to your repository. Consider making use of an Azure Key Vault instead.&lt;/p&gt;
&lt;p&gt;Sample helper&lt;/p&gt;
&lt;p&gt;You will need to install the following package&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;22&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npm install -D @azure/keyvault-secrets&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npm install -D @azure/identity&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will need to have at minimum the Azure IAM &lt;code class=&quot;language-text&quot;&gt;Key Vaults Secret User&lt;/code&gt; role assigned.&lt;/p&gt;
&lt;h2&gt;Automation Plan Checklist&lt;/h2&gt;
&lt;p&gt;Here is a list of questions you can ask yourself about what you want to automate so you can have a clear plan of action before you start. If you roll with the punches, you will be a slave to so many things that you will have much more control by planning and deciding.&lt;/p&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What language am I going to target?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How am I going to use fixtures?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What scenarios do I need isolation for?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What state do I need to share among multiple tests?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What are the most important things to automate? 💡Prioritize critical paths
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What are my blockers?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need static data?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need setup scripts?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Can this data always be available?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need cleanup scripts?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Can I group these into common themes that I can run as parameterized tests?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How am I going to structure and name my tests?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What things are required by multiple tests that I can make helpers for?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to test for accessibility?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What browsers do I need to target?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What devices do I need to emulate?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What viewports am I interested in?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate locales?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate time zones?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate system permissions?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate geolocation?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate colors schemes and media?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate being offline?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What are the tough challenges I need to solve?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How am I going to handle authentication?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to share the authentication state among multiple tests?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have to worry about MFA?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have to emulate failing requests?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Am I ready to automate runs in CI?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How will I report on failing tests and how can I get more details on that?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have everything working locally consistently?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How many workers can my CI handle?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have exit hatches for my CI to preserve resources?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What type of reports do I want to ship?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I want to automate retries on fail?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have linting in place?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have any flaky tests to address?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have to worry about things like VPN requirements?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What is the best time to run the automations? Are there potential interruptions in that window like deployments?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have any reason to update the default timeouts? (Expect 5s, Test timeout 30s)
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Does this need to be global or per test?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Are there any out-of-the-box packages that can simplify my test efforts?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Are there scenarios I can make use of visual comparisons?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to save videos of my test runs?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How am I going to handle secrets?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Have I setup a code review process?&lt;/li&gt;
&lt;/ul&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk17 { color: #808080; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk5 { color: #D16969; }
  .dark-default-dark .mtk6 { color: #D7BA7D; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Report on team activity for DevOps Pull Requests]]></title><description><![CDATA[Photo by Towfiqu barbhuiya on Unsplash Report on team activity for DevOps Pull Requests The following PowerShell script, , is designed to…]]></description><link>http://www.drunkonmonads.com/pr-activity/</link><guid isPermaLink="false">http://www.drunkonmonads.com/pr-activity/</guid><pubDate>Sat, 28 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@towfiqu999999?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Towfiqu barbhuiya&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/person-in-blue-white-and-red-plaid-long-sleeve-shirt-reading-book-Q69veNk1iJQ?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Report on team activity for DevOps Pull Requests&lt;/h1&gt;
&lt;p&gt;The following PowerShell script, &lt;code class=&quot;language-text&quot;&gt;GetPullRequestDetails&lt;/code&gt;, is designed to retrieve and analyze pull request (PR) details from an Azure DevOps repository. By providing insights into the number of PRs created and reviewed by specified users, it aids in understanding team contributions over time and encouraging balance.&lt;/p&gt;
&lt;p&gt;The function &lt;code class=&quot;language-text&quot;&gt;GetPullRequestDetailsXX&lt;/code&gt; takes four parameters:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;$org: The Azure DevOps organization name.&lt;/li&gt;
&lt;li&gt;$project: The project name within the organization.&lt;/li&gt;
&lt;li&gt;$repo: The repository name.&lt;/li&gt;
&lt;li&gt;$token: The Personal Access Token (PAT) for authentication.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Creating a Personal Access Token (PAT)&lt;/h2&gt;
&lt;p&gt;To use this script, a PAT with appropriate permissions is required. Follow these steps to create a PAT:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Navigate to Azure DevOps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Go to your Azure DevOps organization URL (e.g., &lt;a href=&quot;https://dev.azure.com/%7Byour_organization%7D&quot;&gt;https://dev.azure.com/{your_organization}&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Access User Settings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Click on your profile picture in the upper-right corner and select “Personal access tokens”.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a New Token:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Click on “New Token”.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set Token Details:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Name your token appropriately (e.g., “Pull Request Analysis Token”).&lt;/li&gt;
&lt;li&gt;Set the expiration period as required.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select Scopes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Under “Scopes”, select:
&lt;ul&gt;
&lt;li&gt;Code (Read) for reading repository data.&lt;/li&gt;
&lt;li&gt;Code (Status) for accessing PR status information.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create and Copy Token:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Click “Create” and copy the generated token. Store it securely as it won’t be shown again.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;powershell&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetPullRequestDetails&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$org&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$project&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$repo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$token&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    )&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$base64AuthInfo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Convert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]::ToBase64String([&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Text.Encoding&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]::ASCII.GetBytes((&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;{0}:{1}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -f &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;test&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$token&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# comma separated list of valid users, i.e @(&amp;#39;one&amp;#39;, &amp;#39;two&amp;#39;, &amp;#39;three&amp;#39;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$validUsers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;USERS&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$allPRs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;do&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$uri&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;https://dev.azure.com/&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$org&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$project&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;/_apis/git/repositories/&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$repo&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;/pullRequests?api-version=5.0&amp;amp;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;`$&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;top=100&amp;amp;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;`$&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;skip=&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;amp;searchCriteria.status=all&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$i&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; += &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;100&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Write-Output&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$uri&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Invoke-RestMethod&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -Method Get -Uri &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$Uri&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -ContentType &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;application/json&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -Headers &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Authorization&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Basic {0}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -f &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$base64AuthInfo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$allPRs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; += &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.value&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$result&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.count&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -lt &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;break&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$endDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get-Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).Date&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$startDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$endDate&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.AddDays&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;-30&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Initialize hash tables for counts&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$createdPRsAllTime&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$createdPRsLast30Days&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewedPRsAllTime&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewedPRsLast30Days&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;{}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$validUsers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$createdPRsAllTime&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$createdPRsLast30Days&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewedPRsAllTime&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewedPRsLast30Days&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$pr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$allPRs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$creator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$pr&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.createdBy.displayName&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$pr&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.reviewers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where-Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -in &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$validUsers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ForEach-Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$prCreationDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;datetime&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]::Parse(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$pr&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.creationDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Handle creation&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$validUsers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -contains &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$creator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$createdPRsAllTime&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$creator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] += &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$prCreationDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -ge &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$startDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -and &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$prCreationDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -le &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$endDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$createdPRsLast30Days&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$creator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] += &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Handle review&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewedPRsAllTime&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] += &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$prCreationDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -ge &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$startDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -and &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$prCreationDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -le &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$endDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewedPRsLast30Days&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] += &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Output tables sorted by value in descending order&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Write-Output&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;All-time Created PRs by user:&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$createdPRsAllTime&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.GetEnumerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sort-Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Value -Descending | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Format-Table&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -AutoSize&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Write-Output&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Last 30 days Created PRs by user:&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$createdPRsLast30Days&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.GetEnumerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sort-Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Value -Descending | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Format-Table&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -AutoSize&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Write-Output&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;All-time Reviewed PRs by user:&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewedPRsAllTime&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.GetEnumerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sort-Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Value -Descending | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Format-Table&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -AutoSize&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Write-Output&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Last 30 days Reviewed PRs by user:&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$reviewedPRsLast30Days&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.GetEnumerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sort-Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Value -Descending | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Format-Table&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -AutoSize&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Write-Output&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Finish. Total Pull Request count: $(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$allPRs&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.Count&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;)&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;GetPullRequestDetails -org &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;[org name]&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -project &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;[PROJECT NAME]&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -repo &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;[REPO NAME]&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -token &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;[PAT]&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Key Operations&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Authentication:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The script encodes the PAT into a Base64 string for secure authorization in API requests.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fetching Pull Requests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The script constructs a URI to request PR data from Azure DevOps, iterating through pages of results (up to 100 PRs per page) until all PRs are retrieved.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Filtering and Counting PRs:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The script initializes hash tables to count PRs created and reviewed by specified users, both all-time and within the last 30 days.&lt;/li&gt;
&lt;li&gt;It iterates through all PRs, updating counts based on PR creation and review activities.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Output:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The script outputs sorted tables of PR counts for each user, distinguishing between all-time and the last 30 days.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk6 { color: #D7BA7D; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Playwright best practices]]></title><description><![CDATA[Photo by Igor Omilaev on Unsplash Playwright best practices ✅ DO keep the ethos of Playwright in mind. The tool is simple and does two…]]></description><link>http://www.drunkonmonads.com/playwright-best-practices/</link><guid isPermaLink="false">http://www.drunkonmonads.com/playwright-best-practices/</guid><pubDate>Sat, 28 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@omilaev?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Igor Omilaev&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/two-hands-touching-each-other-in-front-of-a-pink-background-gVQLAbGVB6Q?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Playwright best practices&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; keep the ethos of Playwright in mind. The tool is simple and does two things and two things well, perform actions and assert state against expectations. Unlike a lot of other traditional tools, having to wait for things prior to actions or asserts &lt;strong&gt;is not a thing&lt;/strong&gt; and when done is usually a smell of something else being wrong.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These design choices allow Playwright users to forget about flaky timeouts and racy checks in their tests altogether.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; familiarize yourself with useful commands&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests headless&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests in debug mode&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --debug&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests with parallelization disabled&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --workers=1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run tests with fail-fast&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --max-failures=10&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests with tracing on&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# this should always be used on CI runs&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --trace on&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run a specific test by file name&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [test-file-name].ts&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run a specific test by test title&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -g [target title]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run tests that contain certain string in the file name&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [target-string] &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# target strings can be chained&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run specific tests by  directory&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; test/[directory-name] &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# directories can be chanined&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests in headed mode&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --headed&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all tests in a specific browser&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --project webkit &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# --project can be chained&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# view last run test report&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright show-report&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run all test with the UI&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --ui&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# run the code gen to generate tests off a browser interaction&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright codegen [optional-url]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# get help 🆘&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --help&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; familiarize yourself with the Playwright &lt;a href=&quot;https://playwright.dev/docs/trace-viewer-intro&quot;&gt;tracing and trace viewer.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; familiarize yourself with the various test &lt;a href=&quot;https://playwright.dev/docs/test-annotations&quot;&gt;annotations&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider targeting the &lt;a href=&quot;https://nodejs.org/en/download&quot;&gt;latest LTS node version&lt;/a&gt; at the point of creating a new Playwright project. This ensures that you start of with the latest guaranteed support with the widest compatibility and stability.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Consider using &lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;NVM&lt;/a&gt; or an alternative, to manage your node versions especially if you are likely to work on multiple things that may end up having different node version requirements.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright&quot;&gt;official Playwright VS Code extension&lt;/a&gt; for an improved experience.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The VS Code test runner runs your tests on the default browser of Chrome. To run on other/multiple browsers click the play button’s dropdown and choose another profile or modify the default profile by clicking &lt;code class=&quot;language-text&quot;&gt;Select Default Profile&lt;/code&gt; and select the browsers you wish to run your tests on.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; keep your playwright and related dependencies up to date. By updating regularly you keep up with the new features, continued improvements in browser support, bug fixes, compatibility with new features etc. Incrementally updating tends to be much easier than a big bang when you finally need a specific version, especially when dealing with breaking changes.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npm install -D @playwright/test@latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Also download new browser binaries and their dependencies:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright install --with-deps&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# check the version&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright --version&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;Consider &lt;a href=&quot;https://docs.npmjs.com/cli/v10/commands/npm-outdated/&quot;&gt;npm-outdated&lt;/a&gt; as a tool to manage your dependencies.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Consider using the &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=pflannery.vscode-versionlens&quot;&gt;Version Lens extension in VS Code&lt;/a&gt; to check for outdated packages and update them on the click of a button.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the page object model approach to separate the management of a single page’s logic into one source of truth for a clean code structure that encourages the single responsibility making the maintenance of a large test suite over time easier.&lt;/p&gt;
&lt;p&gt;This generally makes your tests easier to read at the top level, example:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;given valid details, creating a new credit application from scratch should succeed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BusinessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerificationPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BusinessVerificationPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documentsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DocumentsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetails&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BusinessDetailsBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerification&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BusinessVerificationBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DocumentsBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// submit business details&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;goto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;assertInitialState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetails&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessDetailsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// submit business verification details&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerificationPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;assertInitialState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerificationPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerification&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;businessVerificationPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;submitManualUpload&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// upload documents&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documentsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;assertInitialState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documentsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;fill&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documents&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;documentsPage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A page object model class is generally just a class that accepts a page (or more) and encapsulates any logic about that page like locators, assertions, actions etc. Here is a sample skeleton&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SamplePage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;doneButton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;doneButton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getByRole&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;button&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Done&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;assertInitialState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;goto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;page&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;goto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;submit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;doneButton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;click&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; adopt fakers for creating random yet realistic test data. For TypeScript tests, the library &lt;a href=&quot;https://fakerjs.dev/&quot;&gt;Faker JS&lt;/a&gt; is an excellent choice for this.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; adopt a builder model to separate the creation of test data from everything as with one source of truth that allows for a test suite to remain maintainable. Sample:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;LandLordBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;LandLord&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;LandLord&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;override&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;faker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;person&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;fullName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cellphoneNumber&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`0&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;faker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;numeric&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;emailAddress&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;faker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;internet&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;leaseStartDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;faker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;past&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;leaseEndDate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;faker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;future&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;# &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Example&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;usage&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;landlord&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;LandLordBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This example relies on the following base implementation.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;withBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;withMany&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ignoreProperty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;abstract&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;implements&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: { [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } = {};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;typeConstructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extractPropertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;withBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extractPropertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;withMany&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuilderBase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extractPropertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;values&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;abstract&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ignoreProperty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extractPropertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyExpr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;propertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;createInstance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;instance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;createInstance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;typeConstructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extractPropertyName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;([^&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Couldn&amp;#39;t extract property name.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;parts&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DynamicBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;constructor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;typeCtor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;typeCtor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;thatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Method not implemented.&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt;  consider configuring a base URL for your tests so this can be defined in one place and reused across your tests.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;defineConfig&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;baseURL:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;http://127.0.0.1:3000&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt;  consider reading any application configuration, regardless of source (environment variables, key vault secrets etc), in a central run once fixture.&lt;/p&gt;
&lt;p&gt;Example. This will pull values from a .env file using &lt;a href=&quot;https://www.npmjs.com/package/dotenv&quot;&gt;dotenv&lt;/a&gt; and pull user secrets from an &lt;a href=&quot;https://azure.microsoft.com/en-gb/products/key-vault&quot;&gt;Azure Key Vault&lt;/a&gt; using a getSecret utility method.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@playwright/test&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotenv&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;process&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;getSecret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;../helpers/secrets&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ConfigurationFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ConfigurationFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({}, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;secrets&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;userPassword:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getSecret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;user-password&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;imitateEmailAuth:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getSecret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;websocket-auth&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;userEmail:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;UserEmail&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;secrets&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;getSecret utility&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@azure/identity&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;SecretClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@azure/keyvault-secrets&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;credential&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DefaultAzureCredential&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;vaultName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;[vault name]&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`https://&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;vaultName&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;.vault.azure.net`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SecretClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;credential&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;/**&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt; * Retrieves a secret from Azure Key Vault based on the given secret name.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt; * &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; The name of the secret to retrieve.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt; * &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@returns&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; The value of the secret as a string.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt; * &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;@throws&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; Will throw an error if unable to retrieve the secret.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt; */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getSecret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;secret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getSecret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;secret&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; write tests that assert the visible behaviour of your application and not on the inner workings. This will make your tests more resilient to changes in the underlying implementation. Examples of good things to check&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Elements on the page and their state i.e. what is visible, what is enabled etc.&lt;/li&gt;
&lt;li&gt;The URL of the page&lt;/li&gt;
&lt;li&gt;The title of the page&lt;/li&gt;
&lt;li&gt;A screenshot of the page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Examples of things that may be less resilient to changes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The exact structure of the DOM&lt;/li&gt;
&lt;li&gt;The CSS classes used on elements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; critically think through and configure the desired browsers and devices to run your tests on. This will ensure that your tests are running on the platforms that are most important to you and will help you catch issues early.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;defineConfig&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;projects:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;chromium&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Desktop Chrome&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;firefox&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Desktop Firefox&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;webkit&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Desktop Safari&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    } &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/* Test against mobile viewports. */&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Mobile Chrome&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Pixel 5&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Mobile Safari&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;iPhone 12&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    } &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/* Test against branded browsers. */&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Microsoft Edge&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Desktop Edge&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;], &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;channel:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;msedge&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Google Chrome&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;use:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Desktop Chrome&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;], &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;channel:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;chrome&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; fast track your process by leveraging the &lt;a href=&quot;https://playwright.dev/docs/codegen-intro&quot;&gt;Playwright test generator&lt;/a&gt; to create tests for you. This will give you a good starting point and you can then modify the tests to suit your needs.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;10&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npx playwright codegen [optional-url]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;You can also generate tests using &lt;a href=&quot;https://playwright.dev/docs/test-use-options&quot;&gt;emulation&lt;/a&gt; to generate a test for a specific viewport, device, color scheme, as well as emulate the geolocation, language or timezone.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; enable retries on CI to make your tests more resilient to flakiness.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; enable tracing to help diagnose failing tests in CI.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Traces and debugging can also be leveraged locally to diagnose issues with your tests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of test hooks (&lt;code class=&quot;language-text&quot;&gt;test.describe&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;test.beforeEach&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;test.afterEach&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;test.beforeAll&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;test.afterAll&lt;/code&gt;) for grouping and granular tests to make sure each test is specific and focused. This will make it easier to diagnose failures and will make your tests more resilient to changes in the application.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; keep up with the [Playwright release notes](&lt;a href=&quot;https://playwright.dev/docs/release-notes&quot;&gt;Release notes | Playwright&lt;/a&gt;) as a nice way to see what new APIs are being released.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; setup linting for your playwright tests with the [ESLint plugin for Playwright.](&lt;a href=&quot;https://www.npmjs.com/package/eslint-plugin-playwright&quot;&gt;eslint-plugin-playwright - npm (npmjs.com)&lt;/a&gt;). Enable caching with your linting for faster subsequent runs.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;11&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npm init @eslint/config@latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sample .eslintrc.json config&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;12&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;parser&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;@typescript-eslint/parser&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;parserOptions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;ecmaVersion&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;sourceType&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;module&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;plugins&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;@typescript-eslint&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;extends&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;eslint:recommended&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;plugin:@typescript-eslint/recommended&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;plugin:playwright/recommended&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;rules&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {},&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;env&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;browser&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;es2021&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;13&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;# in package.json&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;scripts&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;lint&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;eslint &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;**/*.ts&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; --cache&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;lint-staged&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;*.ts&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;eslint --cache&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider &lt;a href=&quot;https://github.com/lint-staged/lint-staged&quot;&gt;lint staged&lt;/a&gt; as a way to be able to run linting only for the files that you have just changed. &lt;code class=&quot;language-text&quot;&gt;npm install -D lint-staged&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;14&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;# in package.json&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;lint-staged&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;*.ts&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;eslint --cache&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⚠️ &lt;strong&gt;DO&lt;/strong&gt; give close attention to the need for any waits or sleeps in your tests. This is a common source of flakiness and should in most cases not be necessary given how Playwright is designed to work.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Playwright assertions are designed in a way that they describe the expectations that need to be eventually met.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Playwright automatically waits for the wide range of actionability checks to pass before performing each action.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of an .env file to have a single source of truth for environment values. You can conveniently load env files globally by adding this into your &lt;code class=&quot;language-text&quot;&gt;playwright.config.ts&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;15&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;defineConfig&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;devices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@playwright/test&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotenv&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Read from default &amp;quot;.env&amp;quot; file.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;dotenv&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; write custom assertions to simplify assertions you use in combination or common things you assert that require custom logic.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;16&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@playwright/test&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;baseExpect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@playwright/test&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;baseExpect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toBeVisibleAndEmpty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assertionName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;toBeVisibleAndEmpty&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;isVisible&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;isVisible&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;isVisible&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`expected locator to be visible`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pass:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;locator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;textContent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;isEmpty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() === &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;isEmpty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`expected locator to be empty, but got &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pass:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`locator is visible and empty`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pass:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assertionName&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO&lt;/strong&gt; not hard code secrets in tests or any artifact that will be committed to your repository. Consider making use of an Azure Key Vault instead.&lt;/p&gt;
&lt;p&gt;Sample helper&lt;/p&gt;
&lt;p&gt;You will need to install the following package&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;17&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npm install -D @azure/keyvault-secrets&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;npm install -D @azure/identity&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will need to have at minimum the Azure IAM &lt;code class=&quot;language-text&quot;&gt;Key Vaults Secret User&lt;/code&gt; role assigned.&lt;/p&gt;
&lt;h2&gt;Automation Plan Checklist&lt;/h2&gt;
&lt;p&gt;Here is a list of questions you can ask yourself about what you want to automate so you can have a clear plan of action before you start. If you roll with the punches, you will be a slave to so many things that you will have much more control by planning and deciding.&lt;/p&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What language am I going to target?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How am I going to use fixtures?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What scenarios do I need isolation for?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What state do I need to share among multiple tests?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What are the most important things to automate? 💡Prioritize critical paths
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What are my blockers?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need static data?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need setup scripts?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Can this data always be available?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need cleanup scripts?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Can I group these into common themes that I can run as parameterized tests?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How am I going to structure and name my tests?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What things are required by multiple tests that I can make helpers for?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to test for accessibility?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What browsers do I need to target?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What devices do I need to emulate?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What viewports am I interested in?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate locales?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate time zones?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate system permissions?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate geolocation?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate colors schemes and media?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to emulate being offline?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What are the tough challenges I need to solve?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How am I going to handle authentication?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to share the authentication state among multiple tests?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have to worry about MFA?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have to emulate failing requests?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Am I ready to automate runs in CI?
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How will I report on failing tests and how can I get more details on that?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have everything working locally consistently?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How many workers can my CI handle?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have exit hatches for my CI to preserve resources?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What type of reports do I want to ship?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I want to automate retries on fail?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have linting in place?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have any flaky tests to address?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have to worry about things like VPN requirements?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What is the best time to run the automations? Are there potential interruptions in that window like deployments?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I have any reason to update the default timeouts? (Expect 5s, Test timeout 30s)
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Does this need to be global or per test?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Are there any out-of-the-box packages that can simplify my test efforts?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Are there scenarios I can make use of visual comparisons?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Do I need to save videos of my test runs?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; How am I going to handle secrets?&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Have I setup a code review process?&lt;/li&gt;
&lt;/ul&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk5 { color: #D16969; }
  .dark-default-dark .mtk6 { color: #D7BA7D; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Writing effective Postman tests]]></title><description><![CDATA[Photo by Audrey Mari on Unsplash Writing Effective Postman Tests ✅ DO maintain a hierarchy of your tests following the same structure as the…]]></description><link>http://www.drunkonmonads.com/postman-best-practice/</link><guid isPermaLink="false">http://www.drunkonmonads.com/postman-best-practice/</guid><pubDate>Sat, 28 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@au_mari_?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Audrey Mari&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/person-searching-inside-cargo-box-during-daytime-iLaCOseBCTU?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Writing Effective Postman Tests&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; maintain a hierarchy of your tests following the same structure as the URLs of the API being tested and write clear, descriptive names for each test case. This helps ensure that anyone reviewing the tests can understand their purpose at a glance.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;POST /api/user/&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;GET /api/users/1&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;PUT /api/users/1&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;DELETE /api/users/1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;POST /api/products/&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;GET /api/products/1&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;PUT /api/products/1&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;DELETE /api/products/1&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;May be structured as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;users
&lt;ul&gt;
&lt;li&gt;create users&lt;/li&gt;
&lt;li&gt;get users&lt;/li&gt;
&lt;li&gt;update users&lt;/li&gt;
&lt;li&gt;delete users&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;products
&lt;ul&gt;
&lt;li&gt;create products&lt;/li&gt;
&lt;li&gt;get products&lt;/li&gt;
&lt;li&gt;update products&lt;/li&gt;
&lt;li&gt;delete products&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This structure helps in organizing tests and makes it easier to locate specific test cases.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; group related tests into collections for easier management and execution. This also helps in organizing tests by functional area or API endpoint.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use environment variables to store and manage test data, such as API keys and server URLs. This promotes reusability and keeps sensitive data secure.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ensure that only the current values ever have the secret values set and not the initial value. This prevents accidental exposure of sensitive information as the collection is shared or exported.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; incorporate both positive and negative test cases to ensure your API behaves correctly under various conditions. When asserting response bodies, consider both expected and unexpected values to have good coverage. For example, if you expect a response body to include validation messages for an expected failed input, also check that the response body does not include validation messages for an expected successful input or anything additional.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Response body has the expected nested errors&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;responseBody&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedErrors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Company.Contacts&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;#39;Contacts&amp;#39; must not be empty.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Company.Addresses&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;#39;Addresses&amp;#39; must not be empty.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Company.CompanyName&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;#39;Company Name&amp;#39; must not be empty.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedErrors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;responseBody&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;have&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;property&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;responseBody&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;eql&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;actualErrorKeys&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;responseBody&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedErrorKeys&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedErrors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedErrorKeys&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;actualErrorKeys&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;sort&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;actualErrorKeys&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;eql&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedErrorKeys&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use Postman’s &lt;a href=&quot;https://learning.postman.com/docs/writing-scripts/pre-request-scripts/&quot;&gt;pre-request scripts&lt;/a&gt; to set up any prerequisites your tests need. This can include generating test data or configuring the request in a specific way.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://learning.postman.com/docs/writing-scripts/pre-request-scripts/&quot;&gt;Pre-request scripts&lt;/a&gt; can be used to set up test theories such as running the same test multiple times with different data to ensure consistency and maintain a single test.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Here is a simple example that sets multiple statement types for use in a request&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;statements-count&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) ?? &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;gt;= &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ? &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;statements-count&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;statementTypes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Month&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Life&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Casual&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Epic&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;statementType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;statementTypes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;statement-type&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;statementType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A test can then use this information and trigger new requests&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Status code is 204 No Content&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;have&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;204&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;statements-count&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) || &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;lt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;++;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;statements-count&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;counter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;postman&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setNextRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;requestName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;} &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;unset&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;statements-count&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make assertions specific and meaningful. Avoid generic messages like “Test passed” or “Test failed”. Instead, clearly state what was expected versus what was observed. It is usually best to have granular tests, for example, if you want to assert the status code, the response body and the response header, this would be best done as three separate tests.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; organize tests logically within each request. Start with simpler tests (like status code checks) and move towards more complex assertions (like content validation) and ensure consistency across all tests.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; include infrastructure and security validations as part of your tests. Check for things like rate limiting, authentication, and authorization mechanisms to ensure the API behaves as expected.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; regularly review and update your tests to reflect changes in the API. Obsolete tests can lead to false positives or unnoticed issues.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use chaining requests to simulate real-world use cases where multiple API calls depend on each other. Extract data from one request and use it in another to maintain test flow. For example, you can have a test that creates a new record and then another test that retrieves the record.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; share your collections with team members for collaborative testing and feedback. Use Postman Workspaces to facilitate teamwork.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Ensure that only the current values ever have the secret values set and not the initial value. This prevents accidental exposure of sensitive information as the collection is shared or exported.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Ensure that the workspace is set to private if the collection contains sensitive information and is only shared with team members who need access to the collection.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; integrate your Postman collections with &lt;a href=&quot;https://learning.postman.com/docs/integrations/ci-integrations/&quot;&gt;CI/CD&lt;/a&gt; pipelines using &lt;a href=&quot;https://learning.postman.com/docs/collections/using-newman-cli/command-line-integration-with-newman/&quot;&gt;Newman&lt;/a&gt;, Postman’s command-line collection runner, to automate your testing process.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; monitor API performance and response times in addition to functional correctness. Use Postman’s visualizer feature to represent response times graphically for easier analysis.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider edge cases and limit conditions in your tests. This helps in uncovering potential issues that might not be evident in typical use cases.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; document your testing strategy and share it with your team. Include guidelines on how to write, organize, and execute tests, ensuring consistency across the board.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; encourage peer reviews of test collections to foster knowledge sharing and improve test quality. Constructive feedback can lead to more robust and effective tests.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; utilize Postman’s reporting tools to generate insights on test runs. &lt;a href=&quot;https://learning.postman.com/docs/collections/using-newman-cli/command-line-integration-with-newman/&quot;&gt;Newman&lt;/a&gt; has inbuilt reporters that can be configured with Azure Dev Ops Pipelines, among other &lt;a href=&quot;https://learning.postman.com/docs/integrations/ci-integrations/&quot;&gt;CI/CD integrations&lt;/a&gt;. Share these reports with your team or stakeholders to inform them about the API’s health and behaviour.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of JavaScript by following best practices and ensuring consistency in your scripts. Use comments to explain complex logic and make your code more readable. Avoid commenting on every line, however.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; thoroughly document each request within your collection. Provide a clear description of what the request does, including its purpose, any specific parameters it uses, and what kind of response it expects. Use Postman’s description field for this purpose.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Employ Markdown syntax in your request and folder descriptions for better readability. Postman supports Markdown, allowing you to format text, insert links, and even embed images to make your documentation more comprehensive and user-friendly.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; document any dependencies or external variables that your collection requires. If your collection depends on specific environment or global variables, mention these in the collection’s overview section along with instructions on how to set them up.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the collection’s overview section to provide a high-level description of the collection’s scope, usage instructions, and any other important information that users should know before they start using it.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; organize your collection logically, using folders to group related requests. This not only helps with navigation but also allows you to document sections of your API in a structured manner.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use Postman’s built-in &lt;a href=&quot;https://learning.postman.com/docs/writing-scripts/script-references/variables-list/&quot;&gt;dynamic variables&lt;/a&gt; for common values such as timestamps, UUIDs, and random integers. This reduces the need for external data sources and simplifies your test setup.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This allows for unique, yet consistent and real-world data to be used in tests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider collections that make use of &lt;a href=&quot;https://learning.postman.com/docs/collections/running-collections/working-with-data-files/&quot;&gt;test input data&lt;/a&gt; to automate the testing of APIs with various input combinations&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; leverage &lt;a href=&quot;https://blog.postman.com/introducing-postbot-postmans-new-ai-assistant/&quot;&gt;Postbot&lt;/a&gt; to automatically generate tests for your API endpoints. This is especially useful when starting tests for a new API or when you want to quickly expand your test coverage.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://blog.postman.com/introducing-postbot-postmans-new-ai-assistant/&quot;&gt;Postbot&lt;/a&gt; will generate tests based on the responses it gets.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;While this is very nifty and effective. Dumping your response data into Chat GPT is more effective as it will generate more meaningful tests and you can request for additional things to be generated.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Example interaction with Chat GPT&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;markdown&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Given a response with a &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`207`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; multi status and the body below, generate multiple Postman tests to assert the status code, the expected response (given the complete response, match that with response json), that the response has a header &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`X-Correlation-ID`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; that is a valid GUID and that the &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`Strict-Transport-Security`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; header is not empty.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;responses&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;statusCode&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;OK: Resource uploaded successfully.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;resourceId&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Bank Statement - valid pdf.pdf&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;statusCode&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Bad Request: Invalid document provided. Should be one of (JSON, PDF, JPEG, PNG, TIFF, BMP, WEBP)&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;resourceId&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Transaction Data - invalid extension.php&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Response&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Status code is 207&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;have&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;207&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;responses&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;statusCode&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;OK: Resource uploaded successfully.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;resourceId&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Bank Statement - valid pdf.pdf&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;statusCode&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;message&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Bad Request: Invalid document provided. Should be one of (JSON, PDF, JPEG, PNG, TIFF, BMP, WEBP)&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;resourceId&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Transaction Data - invalid extension.php&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Response body matches expected response&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;eql&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;X-Correlation-ID is present and is a valid UUID&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;uuidRegex&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;^&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;0-9a-f&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;{8}&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;0-9a-f&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;{4}&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;1-5&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;0-9a-f&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;{3}&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;89ab&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;0-9a-f&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;{3}&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;0-9a-f&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;{12}&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mtk5&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;correlationId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;X-Correlation-ID&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;correlationId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;match&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;uuidRegex&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Strict-Transport-Security header is not empty&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;hstsHeader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;headers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Strict-Transport-Security&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;pm&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;hstsHeader&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;empty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the &lt;a href=&quot;https://learning.postman.com/docs/collections/running-collections/intro-to-collection-runs/&quot;&gt;Collection Runner&lt;/a&gt;’s iteration feature to run flaky tests multiple times. This approach helps in identifying non-deterministic behaviour by running the tests under the same conditions repeatedly.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use pre-request scripts for scenarios where you would like to apply a given change for a test or collection of tests such as dynamically setting header values, overriding environment variables, or setting up data for the test.&lt;/p&gt;
&lt;p&gt;⭐ &lt;strong&gt;DO&lt;/strong&gt; use Postman’s &lt;a href=&quot;https://learning.postman.com/docs/collaborating-in-postman/using-version-control/creating-pull-requests/&quot;&gt;pull request features&lt;/a&gt; to manage changes to collections. This allows team members to propose, review, and discuss changes directly within Postman, streamlining the collaboration process. Use the built-in version control system in Postman as your primary method for tracking changes to collections. avoiding the complexity and overhead of exporting collections to Git for version control whenever possible. While exporting to Git provides a universal way to track changes, it can disconnect the collection from the interactive testing and documentation features of Postman and the output is not user-friendly as the Postman interface for reviewing changes.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;ENSURE&lt;/strong&gt; that all team members are familiar with how to create, review, and merge pull requests within Postman. Providing training or resources can help teams transition to using these features effectively.&lt;/p&gt;
&lt;p&gt;⭐ &lt;strong&gt;DO&lt;/strong&gt; leverage built-in libraries like moment, lodash and querystring to simplify your scripts and make them more readable. These libraries provide a wide range of utility functions that can help you write more efficient and maintainable code. You can also &lt;a href=&quot;https://blog.postman.com/adding-external-libraries-in-postman/&quot;&gt;add external libraries&lt;/a&gt; if required.&lt;/p&gt;
&lt;p&gt;⭐ &lt;strong&gt;DO&lt;/strong&gt; consider Postman tests for more than just testing APIs. You can use Postman to do sanity checks on tools that have APIs. For example, you may have an application that integrates with a CRM where you expect certain data structures to be present in the CRM and in a specific manner for a successful integration. You can write tests to check for this and run this as part of your release sign-off process. Another example is a tedious manual process that can be automated using Postman such as logging into a CRM on each exploratory test to change specific data. You can write a test to do this and run it as part of your exploratory testing with test assertions to ensure the data is changed as expected if an API is available.&lt;/p&gt;
&lt;p&gt;⚠️ &lt;strong&gt;AVOID&lt;/strong&gt; hard-coding values that can change, such as tokens, user IDs, or resource URLs. This can lead to tests that fail when the underlying data changes. Instead, use variables and pre-request scripts to dynamically set these values and have a single source of truth.&lt;/p&gt;
&lt;p&gt;⚠️ &lt;strong&gt;AVOID&lt;/strong&gt; overusing global variables. While global variables are convenient, they can lead to unexpected behaviour if tests are run in a different order or in parallel sessions. Prefer environment variables scoped to specific collections or tests.&lt;/p&gt;
&lt;p&gt;⚠️ &lt;strong&gt;AVOID&lt;/strong&gt;* writing tests that depend on the execution order of other tests. Each test should be able to run independently. If you need to set up data or state, use pre-request scripts or the collection runner’s iteration setup.&lt;/p&gt;
&lt;p&gt;⚠️ &lt;strong&gt;DO NOT&lt;/strong&gt; overlook the importance of cleaning up after your tests. If your tests create or modify data, consider adding steps or scripts to revert these changes. This helps maintain a clean testing environment and prevents interference with subsequent tests.&lt;/p&gt;
&lt;p&gt;Postman can also be used beyond just REST APIs. You can use it to test GraphQL APIs, &lt;a href=&quot;https://www.drunkonmonads.com/SOAP%20with%20Postman/&quot;&gt;SOAP APIs&lt;/a&gt;, and more.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk5 { color: #D16969; }
  .dark-default-dark .mtk6 { color: #D7BA7D; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Promotion deployment strategy Azure pipelines]]></title><description><![CDATA[Photo by Anna Vi on Unsplash Promotion deployment strategy pipelines Are you considering implementing deployment pipelines to multiple…]]></description><link>http://www.drunkonmonads.com/promotion-deployment/</link><guid isPermaLink="false">http://www.drunkonmonads.com/promotion-deployment/</guid><pubDate>Sat, 28 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@anna_vi_travel?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Anna Vi&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/person-driving-a-vehicle-in-the-middle-of-the-road-h7-zoPdyxSk?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Promotion deployment strategy pipelines&lt;/h1&gt;
&lt;p&gt;Are you considering implementing deployment pipelines to multiple environments and unsure about how to structure this? You could have a pipeline per environment and take advantage of &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/pipelines/process/templates?view=azure-devops&amp;#x26;pivots=templates-includes&quot;&gt;templates&lt;/a&gt;) for reuse across the pipelines. You will however need to apply the right level of care to ensure that you deploy the right things across the environments. When QA signs off on a release for instance, are you sure you are deploying the right artifacts/branch as was in QA?&lt;/p&gt;
&lt;p&gt;If you have to rebuild artifacts on promotion to another environment, then you may be doing it wrong as unless you go the extra mile, you cannot guarantee that building the same branch commit twice results in the same artifacts. What if the underlying agent has updated dependencies, what if you do not have version pinning in your application and new dependencies are pulled, what if…?&lt;/p&gt;
&lt;p&gt;Leveraging static and idempotent artefacts like Docker may be a great option as you would have the same artifacts move across environments. Even with that though, if you have to run multiple pipelines, what if you accidentally choose the wrong version on promotion?&lt;/p&gt;
&lt;p&gt;Would a single pipeline that progressively promotes to multiple environments be a potential answer? Much like how &lt;a href=&quot;https://octopus.com/&quot;&gt;Octopus Deploy&lt;/a&gt;) works.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1580px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/01746dc52d2ba47fbd7f796d86db210d/7e99c/a.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 43.99999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABuElEQVR42iVR227iMBCNtitEbIekIeRik8SOcyVXAg1kU6BoKZSW/YB92P//jXVU6ehoZs6xZjwj6d1fEPVT1srhDrAW+DV0M0RiZPnAorIdyCSGXg78CrBGDjYy76Z+rSavZPgnodVFSQYYNNCvAV0Dr4DCR1Jl/QdXJ7o+mMmLKCJaCwZU2CroFUrca6uz9OTWi/aqxdufZgDdlXhm1kd3ezE2n6S7WcXR3V2d+qxFHVxmAlOLqfFeyQ4TJ5T89QmxBtEm3F0RiYDFzbd3en44mzdy/7LzE348vN1tnvTA4SoJ7eRFJqkatFb1IfF6gDhFbhZ3v6HNkB2E3ftquGe/7ml/E0Hx+umUhxnfAItphC3zbmqyZ1p57Zf0ZPKk//CK/Q/NURwOcWRkg1UezeLwDTG5YD3ZQxxCm090bMeNk7aTOZbE761ka7B8bCtkHM6zYZGfFvlxURxHHoOTnvbQ4cIgRlOXkU6zmZtKWnmByxyY/ngeoeFw5pcqLWff8EceU78YVRIhLPZCNTf28rUkEoNXi7AR0FmpCFl0cPic5UZQGkGh09VYwVxIqpsaYS2cz36GMP8Pb6pIDII1b60AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;a&quot;
        title=&quot;&quot;
        src=&quot;/static/01746dc52d2ba47fbd7f796d86db210d/7e99c/a.png&quot;
        srcset=&quot;/static/01746dc52d2ba47fbd7f796d86db210d/0eb09/a.png 500w,
/static/01746dc52d2ba47fbd7f796d86db210d/1263b/a.png 1000w,
/static/01746dc52d2ba47fbd7f796d86db210d/7e99c/a.png 1580w&quot;
        sizes=&quot;(max-width: 1580px) 100vw, 1580px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Convinced? Then you are in the right place. Let’s explore how Azure Pipelines can be used to implement deployment strategies based on environment promotion, using YAML configurations to manage workflows that traditionally relied on UI-based tools like Azure Deployments.&lt;/p&gt;
&lt;p&gt;Environment promotion in CI/CD is the practice of moving software between multiple stages or environments, such as development, QA, UAT, and production. Each environment serves a different purpose and typically requires that certain criteria be met before software is promoted to the next stage. This strategy helps ensure that only well-tested and verified code makes its way to production.&lt;/p&gt;
&lt;p&gt;Let’s take a look at a sample pipeline that has all of this&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;yml&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;batch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;develop&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;master&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;release/*&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;hotfix/*&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# This will deploy the latest of the following branches if any changes are available&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# If you have merges happening to multiple at the same time, this may not work best for you&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;schedules&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;cron&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;0 0 * * *&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Daily Midnight Deployment to QA&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;branches&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;develop&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;release/*&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;hotfix/*&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;ignoreSchedule&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Allows for deploying when run on demand to QA&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Default is to only deploy to QA nightly (when scheduled), this allows an override&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Ignore scheduling rules&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;boolean&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;stages&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;publishArtifactsA&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Publish Artifacts A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;dependsOn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: []&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;publish&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Publish Artifacts A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Ideally pull build tasks from a template to reuse with verification pipelines&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Custom tasks that do actual packaging can then be added&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# - template: [location]/[template].yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo &amp;quot;Publish Artifacts A&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;publishArtifactsB&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Publish Artifacts B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;dependsOn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: []&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;publish&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Publish Artifacts B&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Ideally pull build tasks from a template to reuse with verification pipelines&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Custom tasks that do actual packaging can then be added&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# - template: [location]/[template].yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo &amp;quot;Publish Artifacts B&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;deployToDev&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Deploy to Dev 🟢&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;dependsOn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;publishArtifactsA&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;publishArtifactsB&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Check if skipping deployment to Dev environment is false (i.e., deployment to Dev is required)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Ideally pull build tasks from a template to reuse with verification pipelines&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Custom tasks that do actual packaging can then be added&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# - template: [location]/[template].yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;deployment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;deploy_application&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Deploy Application&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;dev-env&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runOnce&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo &amp;quot;Deploy to Dev&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;deployToQa&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Deploy to QA 🟠&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;dependsOn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;deployToDev&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Deploy if Dev succeeded or was skipped (fast deploy to QA on demand)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Deployment to QA only on a schedule or on demand run with parameter set to true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      or(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;        eq(variables[&amp;#39;Build.Reason&amp;#39;], &amp;#39;Schedule&amp;#39;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;        eq(&amp;#39;${{ parameters.ignoreSchedule }}&amp;#39;, true)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      )&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Ideally pull build tasks from a template to reuse with verification pipelines&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Custom tasks that do actual packaging can then be added&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# - template: [location]/[template].yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;deployment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;deploy_application&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Deploy Application&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;qa-env&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runOnce&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo &amp;quot;Deploy to QA&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;deployToUat&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Deploy to UAT 🟠&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;dependsOn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;deployToQa&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# UAT has an approval gate&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      or(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;        eq(variables[&amp;#39;Build.Reason&amp;#39;], &amp;#39;Schedule&amp;#39;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;        eq(&amp;#39;${{ parameters.ignoreSchedule }}&amp;#39;, true)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      )&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Ideally pull build tasks from a template to reuse with verification pipelines&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Custom tasks that do actual packaging can then be added&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# - template: [location]/[template].yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;deployment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;deploy_application&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Deploy Application&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;uat-env&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runOnce&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo &amp;quot;Deploy to UAT&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;deployToProd&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Deploy to Prod 🔴&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;dependsOn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;deployToUat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;condition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;|&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      or(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;        eq(variables[&amp;#39;Build.Reason&amp;#39;], &amp;#39;Schedule&amp;#39;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;        eq(&amp;#39;${{ parameters.ignoreSchedule }}&amp;#39;, true)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;      )&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Ideally pull build tasks from a template to reuse with verification pipelines&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# Custom tasks that do actual packaging can then be added&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# - template: [location]/[template].yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;deployment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;deploy_application&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Deploy Application&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;prod-env&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;strategy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;runOnce&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;deploy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo &amp;quot;Deploy to Prod&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Multiple stages are defined in the pipeline, each corresponding to a target function/environment. Each stage can specify dependencies on previous stages, ensuring that deployments follow the correct order. Here’s a brief outline:&lt;/p&gt;
&lt;p&gt;This can additionally be used with branch protection on the environment. Recommendations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Loose approach for dev, no protection allowing any branch to be deployed, including ones that have not been integrated via Pull Requests&lt;/li&gt;
&lt;li&gt;Allow only &lt;code class=&quot;language-text&quot;&gt;release/*&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;hotfix/*&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;develop&lt;/code&gt; into QA&lt;/li&gt;
&lt;li&gt;Allow only &lt;code class=&quot;language-text&quot;&gt;release/*&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;hotfix/*&lt;/code&gt;, into UAT and Prod&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/86c9beee34d8773354cdd5bf24e32baa/984b6/b.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 84%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAIAAABSJhvpAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABcUlEQVR42o2TiXKCQBBE+ZdEkEMRdrkUEMEDzxhjUtGK//8beYgVU2WCUs0exfZOT8+gfLzvT6ev/dtuvVoeDp/H46EfhT276zq9P+H0bE8KzrBQxkW+mJdFPhplWTnjmfqe5EMDWQo3DPyKzBv4HoRqb3c7ltnA/H0FoxIP+qvlYjIu5uUs9ORd2gWuU5GF68TxIBumURQWeW6ahqq2NE29CyFchezR7EvhCSGlcGzb7fHYeNYMoiJ7sH3ZoBzbNutVlsRZmpA/3zCmAZVsJss0DL1tGjrj46giQ8bi817T26re1mpwF5di/n+AWJHTJKa8FHk6GQNmnE/60TBNqCLyCHKLi9sYlsQDwOl6AaDhZX3oFhcykWlMgFu7120/DMgCM2mDhm7B0Uo2d9QdFgQ+i9rGRzuM0pbnhMmT+IyelM1FupaKl4Aki8N4zqjRYY1oPT/xE6CyIhMIzdcydKxmWJZJC/IbKD/Wke7jqGV/A1dnyyfx7ueQAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;b&quot;
        title=&quot;&quot;
        src=&quot;/static/86c9beee34d8773354cdd5bf24e32baa/984b6/b.png&quot;
        srcset=&quot;/static/86c9beee34d8773354cdd5bf24e32baa/0eb09/b.png 500w,
/static/86c9beee34d8773354cdd5bf24e32baa/984b6/b.png 630w&quot;
        sizes=&quot;(max-width: 630px) 100vw, 630px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This simple conditional logic in the sample supports complex deployment strategies and mimics the functionality of dedicated deployment tools like Octopus Deploy, which focuses heavily on promoting releases between environments. This is also used hand in hand with branch control on environments, ensuring that certain branches are not promoted past QA, for instance, a developer’s feature branch.&lt;/p&gt;
&lt;p&gt;In an ideal world, the promotion would strictly follow the steps from left to right. However in the real world, you will come across some scenarios where you may want to break the rules, for instance&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You may want to fast deploy to QA without waiting to develop&lt;/li&gt;
&lt;li&gt;You may be working on a hotfix with changes on DEV/QA dependencies like your database that are no longer compatible with Prod, in which case you may want to deploy straight to UAT&lt;/li&gt;
&lt;li&gt;You may have one of those tough days where you just need to get some &lt;code class=&quot;language-text&quot;&gt;quick and safe&lt;/code&gt; hotfix out straight to production&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In such circumstances, you would want the ability to skip stages, which you can do with this structure when you trigger a new run&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 564px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e555b8c895827725bdc7941190bca106/0a8ae/c.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 110.80000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAWCAIAAABPIytRAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAClElEQVR42o1SyXLaQBDVT9iXxHE5hWMDkmbVMtrQhgRGIHaEJAwVX3KJ//+YBhziitepp1bP8qa7X49kmoYQ5m57//j4e1PXxWp1v6nDwFfkNiWYYHQCTI8rGmeObYEjcawwrCTdbrFaZoPBaJgN4XfXT7pxHIX9Xgq2lyZhGDBKjnxwOKPgSIrdxX7mO8J1ncDv2JaAPbj7BDh3dI7M55CQHfMwSyIf7s4Gd57rYKQ+T/Il5x+57WVqOFlOR3MYs+liPoM8Txm+D0k1XGwFke/FUQRlhkHwGdoTmWgG1c2Oa7uO4zpP9rORm8FMSat6Oa2qqq6r9brwHIcxCvzneCMykimSQSSkKgQhRZXbRAb/uHLCq8pJhqHbtlWuIeRqmueTcs7uU892LEvAS/BAfduCWnSNv+RLGkU6w0HgAxxbRFHkBQEI3vFcaHsXvMAHI0zjFTLSbSy8wNvr5LhuYvE+vbltt7GyT15V5COgilcFm8rJerte1HWdj8e71awcxEnU5bmPdcrJu4IxtcmUpgqXt1tgCKxSTCEQI+TDVrXCfas2xQwUg8jVLP8Va0KIQCOcoA/IiJtYt0LfA3lAWJDH9Tudjjew9uT3g0tYt+lBMGjK/oW5zhgpDIpA6BMvzJ/IcVEXi7Ks8zxfl+U2TbtxMvcNkyII/dbYkzluaegHJy2Gbql6w3GT0LZGWoI2Ob6F6QEnZw/YBTCiSCa97ovzodcoBqwa8SKjm7FZjfQiY+WQrvpk2VOqXIfdZV8ph2w7tbJOI+ZngjYk+FL9bOhfPyz93dyqJ+bPhbeb2w8r7865TM2LVHzt2d96FuACbN+6TIwvXe1ckAak3TTwlYG//8WVgZ6mOjr46Er/D4djHDf/AJsQIGpc6yvlAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;c&quot;
        title=&quot;&quot;
        src=&quot;/static/e555b8c895827725bdc7941190bca106/0a8ae/c.png&quot;
        srcset=&quot;/static/e555b8c895827725bdc7941190bca106/0eb09/c.png 500w,
/static/e555b8c895827725bdc7941190bca106/0a8ae/c.png 564w&quot;
        sizes=&quot;(max-width: 564px) 100vw, 564px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The approach motivated here ensures that changes from PR merges only make it as far as the development environment, with a nightly run being the primary way to get changes into QA, coupled with empowering the team to be able to run on demand to get things into QA. In this case however one has to be explicit in this intention by ticking the &lt;code class=&quot;language-text&quot;&gt;Ignore scheduling rules&lt;/code&gt; parameter.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 241px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8fe3d08f986111de5d7baa82789a2d08/62847/d.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 15.352697095435685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAApElEQVR42mMwMDJR9CvQsfMxM9IzNTU1MTays7UxMzUBsqwsLYAMSwtzIMPczNTYyBAoC2QBBY0MDYCIQcfCSXTiB+mw5ghfl5bWtpTk5Oqqqvi42Iz0tLzc3IKC/KKiwpJiIFEAFImNiS4vK83NyQbqNzTQZzA0MlZzT9SydDE3MXR1dQWKWltZAu2BWA60xtzMBMgGWu7i7AR0GdBmiCuMDA0AmhkxD5I+ICYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;d&quot;
        title=&quot;&quot;
        src=&quot;/static/8fe3d08f986111de5d7baa82789a2d08/62847/d.png&quot;
        srcset=&quot;/static/8fe3d08f986111de5d7baa82789a2d08/62847/d.png 241w&quot;
        sizes=&quot;(max-width: 241px) 100vw, 241px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Having things change under the feet of a busy QA team is usually not a good idea and a motivation to give QA teams control of when to get things, however coupling this with nightly runs ensures that this does not become an entirely manual process.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/pipelines/process/approvals?view=azure-devops&amp;#x26;tabs=check-pass&quot;&gt;Environment approval gates&lt;/a&gt;) should also be considered. Recommendations&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Explicit approval requirements, where one more team members have to give the green light for promotion to UAT and Prod. Pay close attention to the duration you choose for the approval expiration.&lt;/li&gt;
&lt;li&gt;Consider business hours gates to control when promotion happens&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/pipelines/process/approvals?view=azure-devops&amp;#x26;tabs=check-pass#exclusive-lock&quot;&gt;Consider exclusive&lt;/a&gt; locks to avoid contention of deployments. This is particularly useful for the development environment if you have all Pull Request merges resulting in deployments, where successive merges can trigger multiple deployments. An exclusive lock will allow only the first through and cancel all the rest except the last one. This is best used with a pipeline that has only one stage per environment, if you have multiple the exclusive lock kicks in on that too.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Azure Pipelines currently lack a feature to cancel all pending approval requests but the latest or at least cancel all prior ones when a later one is approved. This would come in very handy. Manage this well to avoid a bunch of pending approvals. I also recommend making use of a variable and conditions that ensure that unless the team is in a release cycle, where a build is being stabilized for release, UAT and Prod are never considered at all, hence not triggering approval requests that will just be ignored.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Before you panic when you see your first approval blocking a pipeline run, note that Azure Pipelines smartly handles this by yielding back the agent used to run the pipeline. Once approval is given, the pipeline stages/jobs that follow will then be scheduled on another agent. Approvals can be pending for multiple days and that is not an issue at all.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 241px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8fe3d08f986111de5d7baa82789a2d08/62847/d.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 15.352697095435685%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAADCAIAAAAcOLh5AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAApElEQVR42mMwMDJR9CvQsfMxM9IzNTU1MTays7UxMzUBsqwsLYAMSwtzIMPczNTYyBAoC2QBBY0MDYCIQcfCSXTiB+mw5ghfl5bWtpTk5Oqqqvi42Iz0tLzc3IKC/KKiwpJiIFEAFImNiS4vK83NyQbqNzTQZzA0MlZzT9SydDE3MXR1dQWKWltZAu2BWA60xtzMBMgGWu7i7AR0GdBmiCuMDA0AmhkxD5I+ICYAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;d&quot;
        title=&quot;&quot;
        src=&quot;/static/8fe3d08f986111de5d7baa82789a2d08/62847/d.png&quot;
        srcset=&quot;/static/8fe3d08f986111de5d7baa82789a2d08/62847/d.png 241w&quot;
        sizes=&quot;(max-width: 241px) 100vw, 241px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 332px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5101edeb82651cc6c9ed07a0acca92c5/557e0/f.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 62.650602409638545%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABlUlEQVR42o2S6y4DYRCG904Iouo7zrelSim77R66uxV7UI1IVDUS/wgSEncg4QqIuAa/JP6Ky3AH3IHZbFG0YTOZvHuYb2aefTUFUgeplNQVFHSF+SuyW5AF/GBQaAUdMiU5oyTPGGWMoBQcJeGUSJBMgeo/NG2TZk0JNrJ/R+PDrY240+122u1mcz2JoyQKO+2d5mZryzRuOC0qgL6e2RFaAcSos5crWa5RjteCaDWIw6gR+K5j+Z4XRmFQXjgSbAYGFSvg9SBq7Z2GO8dR98wMWiSf45RyTnFsRqa54DmQ8H3bXjHyOL99vnx4vbh/uXp8O79+wqfZ696eGdGBxUryqp8kuyfR9kHcOa56MQLqZzOQ88fOSnGSJ7nx6cmxqYlRnFlyLhhF4IgaM0gxtBj/0XqYVFcMwzQRciOoW7bluo7v1xt4+d5CqSiFGDI2wEqlMj83t1guu7ZdqxlLy0u2VXMcO/A9q2qWirO/m38AU4B+kFJIwVNvpPZIBWeE/Tk2WvLTlV9a7+mfhv0emhri2//EO9uhruB3e7a3AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;f&quot;
        title=&quot;&quot;
        src=&quot;/static/5101edeb82651cc6c9ed07a0acca92c5/557e0/f.png&quot;
        srcset=&quot;/static/5101edeb82651cc6c9ed07a0acca92c5/557e0/f.png 332w&quot;
        sizes=&quot;(max-width: 332px) 100vw, 332px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 625px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/fbbbaba7c7a82988156719a3d73d99bb/b1b4f/g.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 38.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAA7EAAAOxAGVKw4bAAABfklEQVR42lWQy07CQBSGu3Dr2qUYRKWddqbT+5VeaKUtpYVCIhBBg0rideNan8DExLVP5caFO1/EI0QSJ18y/5k55/xzhrm8WJyfzSfjk8l4DOLu9mY+O60G/dPpdHZ5cd2JXwXEUVESCV0hEqypiuvYIJhhVY2Gwzzv9svCsa04arfDAO5M02h5LVdTI4LFv8o1skRVRQbBqBIhBGOBh04CjxDHAgLPYZ4TECsICNN/lRv/32Jix1WZF0WRpUnge2HgR2Hg+YHTzh3/2LQ9SlbZm0UpQEUR/BkSlKNBryyKNOn08u762Wma5uUoyXphOw6hV8sNXSNyNN9SVNyUUUMmvKLIDGwSpYosAaoCJ5JEoasoUQJz2aYR+L5t6mw8Paoe2f5DvXuzl98jM6IYMZALwxq6pmsqYJmGaegHjf1abZdjm3k3Wy6vsjjcWbxzb9/o5XP76WPr+aueXcv8IQM+a9uVs7wG5tkAEfysoHu8kyC7w1mdppVgRacE/wAFw3OHJ03LSgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;g&quot;
        title=&quot;&quot;
        src=&quot;/static/fbbbaba7c7a82988156719a3d73d99bb/b1b4f/g.png&quot;
        srcset=&quot;/static/fbbbaba7c7a82988156719a3d73d99bb/0eb09/g.png 500w,
/static/fbbbaba7c7a82988156719a3d73d99bb/b1b4f/g.png 625w&quot;
        sizes=&quot;(max-width: 625px) 100vw, 625px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A nice thing with approvals is that instead of business hours approval checks, you can also have control of when an approved deployment kicks off by scheduling it on approval. This feature is not available when using the Azure Pipelines extension in Microsoft Teams.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 626px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/95d2b2b9b9018b31585cbd6f7e2c3dd5/ce661/h.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 50.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABnUlEQVR42m1R2U7CQBTtR/isqEihy3QvpVMoHdqydEMRg/Lm8mT8AhIeTNTEn/FP5Em/xwMjiQ+mJ5M703PO3QTFT9phUuWTLJvEAxb2ulE/BGiY+L2E9pjtOLpGDF3jp2noHLZlCnJYeXGxXMyrqqzKosgzWIzSZHpxVUxn6WjCGBuwPuzSJGZR33VsWFim4diWYBHJ1olh4tPxBD8EBqARXVO9tgMZyoEGbPwFx9qRYSGYexn1O4Df8XrdAC8nx7X66Uk3oPd3t/PLGQhEVSAANKKiBXAEXCBAqdwM3siwBVLtskEGNlwGLMI1oH6aJqjlV4ySkM3fZYZ9UxRbzT3EBlFkCDpeu+06iiwhwo23LezmZlDP7XdpFAaWQZSWSBRJllqg4kRaiEGVWk3YoTQ8Ns7qWzFqopQm2TQc5mxUsHGJoDifY+xlmed5hhXwQaIL1Mj7cl1nK3ZUsTZ8OHz5ar5tjp434uun+P598PgRRPHyZoHd8dnwifzFtmdLU6RgLN+steVKWqzU65WyXDfKp45Ph2mMPfHF/IsfFXqIyPqRf5YAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;h&quot;
        title=&quot;&quot;
        src=&quot;/static/95d2b2b9b9018b31585cbd6f7e2c3dd5/ce661/h.png&quot;
        srcset=&quot;/static/95d2b2b9b9018b31585cbd6f7e2c3dd5/0eb09/h.png 500w,
/static/95d2b2b9b9018b31585cbd6f7e2c3dd5/ce661/h.png 626w&quot;
        sizes=&quot;(max-width: 626px) 100vw, 626px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Consider the &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/pipelines/integrations/microsoft-teams?view=azure-devops&quot;&gt;Azure Pipelines integration with Microsoft Teams&lt;/a&gt; to receive notifications of approval requests and provide approvals directly from there.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 600px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9b618322bfd99cbc996092bcf5667a93/dface/i.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 64%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAIAAAAmMtkJAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACAElEQVR42o1STY7TMBQuS+YIDEKlaW0njhPHdhonafqTtKVNpg2TKSNapFkUIbGBBWLHgjUnQEjsOQG3QJyAY3AAXppOmQ0Sn56fEsffi7/vvda7j19fvv8UaTkeT6bTaZqmUkr/AKUUpdT8N1r55S6rVsKjUgo4DUzHcdxbHMgWoMknHMmP2+3zc+Nh2+wYyDCMDiyjZxjdA3oQGDeBMOoi1MUYco8QUpNdRl5Vj95cP8hiLJXWuh+GQRxpyPAcRyHnoetqxiTnkScSl0dKBYwxjHFrqLu/vt3//f3eh9foZv/2qrq6uNityxfrclcUzxeLtVRDIUZQQvkZhJCTMEw4d2ty7Hd/fD77+eXsZtWRwUhJ37KkbfcpVTbrE8IwMghBEHBhCIJ7zbUBLWqRNMbZAHNGQCpsWRa1zNqhxiRK7XrHsillJ+dAcE22bbtYVRBS+SYB2XMdPguCMtCXOrrm3kDKsZAjTwyVSk8+/yUvnswg8jwfxBHnKecTz0uYoxE2EcLgK9wGDoNIIDT5SAbfquppWa6KIrdMEkXRcrlM02w2m8HOfD7fbre7W2w2m/1+X5YllKhbBcvvJ0EwljKklAuZQMMYs2FCOHjqus20wfA0IwTNFEIcDYMa3BtJNXUc7Tj9QBfMCfAdoDtoXpvf1uRDCdwoAS3w9SDyv/AHWHOdGFhSpYIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;i&quot;
        title=&quot;&quot;
        src=&quot;/static/9b618322bfd99cbc996092bcf5667a93/dface/i.png&quot;
        srcset=&quot;/static/9b618322bfd99cbc996092bcf5667a93/0eb09/i.png 500w,
/static/9b618322bfd99cbc996092bcf5667a93/dface/i.png 600w&quot;
        sizes=&quot;(max-width: 600px) 100vw, 600px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 549px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b7ffa19d38cb4ef59d29cdee3ad59d50/ffc28/j.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 83.80000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAIAAABSJhvpAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABkUlEQVR42o2T6U7CUBCF+ygCKpStdC/doEWFspoI/lKjGLf3fwG/yxhiIjZNzp0u986ZM3Nabf/y/PX58fT4cL/bvu73729v41E6MPq2ZVrm4CTMgZHEkec6GiscBr7nyk0chY5t/Zd2BGdgV8mjNInCIWSubRn9HntslEMoNDI369X05npRzKIgYAPWitBo4FA2Rvokz3S9Va+dnTfq5WjUa91OW6NbWqVria5je44tLZXLVj0j+3azLmZTlC+XC5QzMyh63U6/1xUwfLlhIkTESr5GEUaVZ2M0YxIR/TDmWQYmuXrLGy5ADvie07y8gFEl0zOgILKlLKfjOErTJE0SiALfJ5KZJjGRTmlYVRZ70QwK1tWEVRSzNIoCz/V9F/3oRDAYGH9kS/6xPl1QIVQfjgPE0tM+IxKfFTbr3faOTJkQ9IKTnyclIdd4gF455DnUYuN3Zgl+ZC/mxXIxJ+LZerU86LVFcwmUzxDQIX4c5tEntvVWFajKCGBaOKG3moJOW68CVZklTlT/HwS2ZX4DHnDSnKd+gdkAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;j&quot;
        title=&quot;&quot;
        src=&quot;/static/b7ffa19d38cb4ef59d29cdee3ad59d50/ffc28/j.png&quot;
        srcset=&quot;/static/b7ffa19d38cb4ef59d29cdee3ad59d50/0eb09/j.png 500w,
/static/b7ffa19d38cb4ef59d29cdee3ad59d50/ffc28/j.png 549w&quot;
        sizes=&quot;(max-width: 549px) 100vw, 549px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Screenshots of sample runs&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Manual run with default parameter values&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1772px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8c3683c8a504f21187735616f6941cbc/e670e/k.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 21.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAeUlEQVR42o2Naw7EIAiEvZE8BGqsor3/oZbWTbM/NxmYL0PIpLP3ephKkcIiHLA5tj38yn5gcxIra3m8I+R21nVNUmbEMbr3ZpiJcPoYrSpmZprT7zYEgJz0kH42i1LCu7yEQ0x4KJgejuTNN4eSmbgPU/1GAPvwjz77HjFMFyC3nQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;k&quot;
        title=&quot;&quot;
        src=&quot;/static/8c3683c8a504f21187735616f6941cbc/e670e/k.png&quot;
        srcset=&quot;/static/8c3683c8a504f21187735616f6941cbc/0eb09/k.png 500w,
/static/8c3683c8a504f21187735616f6941cbc/1263b/k.png 1000w,
/static/8c3683c8a504f21187735616f6941cbc/e670e/k.png 1772w&quot;
        sizes=&quot;(max-width: 1772px) 100vw, 1772px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Run with Ignore scheduling rules&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1738px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8f528669b2b6493094bf540056da3b5d/97912/l.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 20.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAfklEQVR42m2NCw7DMAhDc6IFkkA+5FP1/oeqm06Tpk0C9GxhcGamkmJgNGZgAvzl+MNOclxr1pJhlZbXHKkKbz7WaBIC+W5tjm5vtjmHIUreqabe2/M8q9xX4n0bTqs57T/wIVMgJq8qkI/vStXzPJB5NPkXJgp7EB/mb+bNF4oBMOgVkpzzAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;l&quot;
        title=&quot;&quot;
        src=&quot;/static/8f528669b2b6493094bf540056da3b5d/97912/l.png&quot;
        srcset=&quot;/static/8f528669b2b6493094bf540056da3b5d/0eb09/l.png 500w,
/static/8f528669b2b6493094bf540056da3b5d/1263b/l.png 1000w,
/static/8f528669b2b6493094bf540056da3b5d/97912/l.png 1738w&quot;
        sizes=&quot;(max-width: 1738px) 100vw, 1738px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Skipping the development environment&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1748px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a3e44ee623275cd628c8df4f0c43362a/b4f5d/m.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 21.999999999999996%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAi0lEQVR42mWNaw7CIBCEOY+lluUN5aX/pd7/NE4hRpMmA/uxO8OyEKNWUkm6SpL4PUnoL8N/58v76Mx682g1OAtryamWrBycW0zh2UrQEn00MYqaBpdWsl557y/mvMlptwbfEe6zYqfYAA6HBAKo0GR4oHW5HQj7YFur3tmREtgphwnwzxMmYw0f4Q/ilTHpQlu3sQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;m&quot;
        title=&quot;&quot;
        src=&quot;/static/a3e44ee623275cd628c8df4f0c43362a/b4f5d/m.png&quot;
        srcset=&quot;/static/a3e44ee623275cd628c8df4f0c43362a/0eb09/m.png 500w,
/static/a3e44ee623275cd628c8df4f0c43362a/1263b/m.png 1000w,
/static/a3e44ee623275cd628c8df4f0c43362a/b4f5d/m.png 1748w&quot;
        sizes=&quot;(max-width: 1748px) 100vw, 1748px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Branch control kicking in&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1573px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9c9092d0c71582787514deffb07a2b6d/b86a3/n.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 32.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAs0lEQVR42m2QCw7EIAhEPVEVRFHrp629/5kWbbdpNpsQfBkEJijPbNGA0Qgjg14ELjZTvHWzvBkmK46u921NwYJJJe5Ho+QQTQ2h1xwJZESrZW9lFRn01uomTIOVd5RCsAgS7F0MYgQQIHqqzCSmQLMUyNq5LQzGi9WwpxfJV7+ZtuXJ7M9jz2sSEb7+r9LDighllrOjce68CyLUkiXI4iP+hIqJz36IW/n0br5v9r3f3+YPMK9IgFZVhpAAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;n&quot;
        title=&quot;&quot;
        src=&quot;/static/9c9092d0c71582787514deffb07a2b6d/b86a3/n.png&quot;
        srcset=&quot;/static/9c9092d0c71582787514deffb07a2b6d/0eb09/n.png 500w,
/static/9c9092d0c71582787514deffb07a2b6d/1263b/n.png 1000w,
/static/9c9092d0c71582787514deffb07a2b6d/b86a3/n.png 1573w&quot;
        sizes=&quot;(max-width: 1573px) 100vw, 1573px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 537px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/61446806b031788861aa45aba2a20069/673a2/o.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 32.2%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAA4klEQVR42m2P646CMBCFeRr/aOm0FQQVULCC9YqXeEHEqGvU19kX3gHUZI3N13Y6mTNzqg2i8PpzOZ9Pu+0m3SfI4347pOlmvT5mWZLsfqOKbIAOIBjwAgbUNOqtpq01bUsGfuB3PddBXNfBdgG+O16+nfbMIpYA9lKW1AVvmIZGdFIlNUZ1TAnOMAtUx95FEeWcE7wZ4//FJVpsW1u/u8+y5TyeTsaLeTxUg77shX0ZhVKOVoFaej0lhMh7fYgdwT3TUEOFfyiHI+8gp1jfJ1N0CZTUqlA4R8Ol52fwOr+K/wDcnlGwmeYeNgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;o&quot;
        title=&quot;&quot;
        src=&quot;/static/61446806b031788861aa45aba2a20069/673a2/o.png&quot;
        srcset=&quot;/static/61446806b031788861aa45aba2a20069/0eb09/o.png 500w,
/static/61446806b031788861aa45aba2a20069/673a2/o.png 537w&quot;
        sizes=&quot;(max-width: 537px) 100vw, 537px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;What about Azure Releases?&lt;/h2&gt;
&lt;p&gt;You can mimic this by making use of the classic Azure Releases. However YAML vs ClickOps! Using YAML for defining your pipelines has several advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Version Control&lt;/strong&gt;: Track changes to the pipeline configurations just as you do with source code.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reusability&lt;/strong&gt;: Templates and parameters allow you to reuse and customize components across different projects or environments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Transparency and Auditability&lt;/strong&gt;: Changes are visible and auditable through commit histories, enhancing security and compliance.&lt;/li&gt;
&lt;/ul&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Technical analysis checklist]]></title><description><![CDATA[Photo by Glenn Carstens-Peters on Unsplash Technical analysis checklist This technical checklist should serve as a reference for things to…]]></description><link>http://www.drunkonmonads.com/technical-analysic-checklist/</link><guid isPermaLink="false">http://www.drunkonmonads.com/technical-analysic-checklist/</guid><pubDate>Sat, 28 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@glenncarstenspeters?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Glenn Carstens-Peters&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/person-writing-bucket-list-on-book-RLw-UC03Gwc?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Technical analysis checklist&lt;/h1&gt;
&lt;p&gt;This technical checklist should serve as a reference for things to consider before starting any technical work. Many checks need to be in place that range from understanding the ticket and establishing that it is ready for development, to determining blockers/dependencies, options, potential challenges and more to ensure that the technical implementation will be as smooth as possible. This can also ensure that other necessary aspects, such as code quality, security, deployment, and maintenance, are considered.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ This checklist is not meant as a ‘gate’ or ‘red tape`. Such a checklist acts as a roadmap, guiding teams through complex processes in a structured yet flexible manner. They ensure thoroughness and adherence to best practices, while also fostering efficiency and clarity in project execution. This is best used as a once-off read as a team to establish how the team gets ready for technical work and as a reference only thereafter as necessary. It is certainly not a checklist in the sense that for each ticket you need to open this and tick things off.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Checklist&lt;/h2&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Is the ticket well understood?
&lt;blockquote&gt;
&lt;p&gt;Read and comprehend the user story or task description thoroughly. Clarify any ambiguities or uncertainties with the relevant stakeholders&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Equally important is understanding the ‘why’ behind the specific change and how it will benefit the client. This will require acquiring a comprehensive business context for both the tickets and the overarching goals&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Is the implementation goal clear?
&lt;blockquote&gt;
&lt;p&gt;Understand what problem or need the software is trying to address&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Does the work item need to be broken down?
&lt;blockquote&gt;
&lt;p&gt;If the user story or task seems complex, break it down into smaller sub-tasks or sub-goals to facilitate better understanding and implementation&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Are there any dependencies or blockers?
&lt;blockquote&gt;
&lt;p&gt;Identify any dependencies or blockers that need to be addressed before the work can be picked up.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Avoid too many dependencies in a Sprint and highlight these.&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clearly mark items that are blocked and identify who is responsible for unblocking the team.&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Is there a clear Sprint Goal and are the Priorities communicated?
&lt;blockquote&gt;
&lt;p&gt;Leverage Azure DevOps functionality to set out a clear Sprint Goal and ensure that priorities are clear&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Is this technically feasible?
&lt;blockquote&gt;
&lt;p&gt;Assess whether the proposed solution is technically feasible within the given constraints (e.g., time, resources, technology stack). Consider potential limitations or technical challenges.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Will this impact existing functionality or other planned work?
&lt;blockquote&gt;
&lt;p&gt;Evaluate the impact of the user story or task on the existing system or codebase. Identify potential areas that may be affected and consider how changes will be implemented.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; What other criteria need to be met to complete this work item?
&lt;blockquote&gt;
&lt;p&gt;Identify things like test coverage, monitoring and observability, performance criteria, security requirements etc.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Is there a clear implementation approach?
&lt;blockquote&gt;
&lt;p&gt;Define an approach or strategy for implementing the user story or task. Consider factors like architecture, code structure, and best practices. Discuss and validate your approach with other technical colleagues&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Has the effort of implementation been estimated?
&lt;blockquote&gt;
&lt;p&gt;Estimate the effort required to complete the user story or task. Break it down into smaller tasks if necessary. Consider the complexity, skill level, and availability of team members.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Has any required documentation been identified?
&lt;blockquote&gt;
&lt;p&gt;Document any assumptions made during the analysis process, as well as decisions taken regarding the implementation approach, design choices, or technology selection.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Technical considerations&lt;/h2&gt;
&lt;p&gt;The following technical considerations should be made as clear as possible as part of the technical analysis&lt;/p&gt;
&lt;ul class=&quot;contains-task-list&quot;&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Required test coverage
&lt;blockquote&gt;
&lt;p&gt;Specify the types of tests that should be implemented, such as unit tests, integration tests, or end-to-end tests.
Identify any special testing requirements, such as performance testing or security testing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Error handling and logging&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Monitoring and observability
&lt;blockquote&gt;
&lt;p&gt;Determine the key metrics, logs, or events that need to be monitored to ensure the system’s health and performance.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Frameworks and tools that can/should be used&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Coding practices/standards that should be adhered to&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Any required configuration&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Any additional steps for the feature to be available&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Artifacts that are expected as part of the implementation (documentation, scripts, Shared Lib contributions etc)&lt;/li&gt;
&lt;li class=&quot;task-list-item&quot;&gt;&lt;input type=&quot;checkbox&quot; disabled&gt; Special performance considerations
&lt;blockquote&gt;
&lt;p&gt;Identify performance requirements, such as response time, throughput, or scalability. Determine any performance testing tools or frameworks that should be used, such as JMeter. Specify any performance optimization techniques or best practices to be followed.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Structurizr local setup]]></title><description><![CDATA[Photo by Amsterdam City Archives on Unsplash Structurizr local setup This requires an installation of Docker on your local machine…]]></description><link>http://www.drunkonmonads.com/structurizr-local/</link><guid isPermaLink="false">http://www.drunkonmonads.com/structurizr-local/</guid><pubDate>Sat, 28 Dec 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@amsterdamcityarchives?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Amsterdam City Archives&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/9tmKEDz03uw?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Structurizr local setup&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;This requires an &lt;a href=&quot;https://docs.docker.com/get-docker/&quot;&gt;installation of Docker&lt;/a&gt; on your local machine.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://structurizr.com/&quot;&gt;Structurizr&lt;/a&gt; builds upon &lt;code class=&quot;language-text&quot;&gt;diagrams as code&lt;/code&gt;, allowing you to create multiple software architecture diagrams from a single model.&lt;/p&gt;
&lt;p&gt;This setup makes use of the &lt;a href=&quot;https://docs.structurizr.com/dsl&quot;&gt;Structurizr DSL&lt;/a&gt;, the recommended option when creating C4 diagrams with Structurizr. Structurizr is specifically designed to support the C4 model for visualising software architecture, by its creator Simon Brown. Diagrams are interactive (e.g. zoom in/out), animatable, embeddable, and include an automatically generated diagram key/legend.&lt;/p&gt;
&lt;h1&gt;Local setup&lt;/h1&gt;
&lt;p&gt;To quickly get up and running run the following docker command&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;docker pull structurizr/lite&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This will pull down the docker image and if you start up a container from this it will start with a default diagram. To create your diagrams, however, you would want to point the docker container to a directory locally with the DSL. For example, if the location is &lt;code class=&quot;language-text&quot;&gt;/Users/you/structurizr&lt;/code&gt;, the command would be&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;docker run -it --rm -p 8080:8080 -v /Users/you/structurizr:/usr/local/structurizr structurizr/lite
&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Your instance of Structurizr Lite is now running and will be available &lt;a href=&quot;http://localhost:8080/&quot;&gt;locally on port 8080&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A recommended approach however will be to create your own &lt;a href=&quot;https://docs.docker.com/compose/&quot;&gt;docker compose&lt;/a&gt; file and in that same directory have a sub directory with your DSL.&lt;/p&gt;
&lt;p&gt;Here is a sample docker compose file.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;yml&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;3.8&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;structurizr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;container_name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;structurizr&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;structurizr/lite:latest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;8080:8080&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;volumes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;./structurizr:/usr/local/structurizr&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case, the Structurizr DSL and any other artefacts like images would be in a sub folder named &lt;code class=&quot;language-text&quot;&gt;structurizr&lt;/code&gt;. The container can be spun up with the command &lt;code class=&quot;language-text&quot;&gt;docker compose up&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Here is a sample for a &lt;code class=&quot;language-text&quot;&gt;workspace.dsl&lt;/code&gt; file you can use as a starter with your local setup.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;workspace {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    model {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        user = person &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;User&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        softwareSystem = softwareSystem &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Software System&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            webapp = container &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Web Application&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                user -&amp;gt; this &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Uses&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            container &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Database&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                webapp -&amp;gt; this &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Reads from and writes to&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    views {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        systemContext softwareSystem {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            include *&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            autolayout lr&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        container softwareSystem {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            include *&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            autolayout lr&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        theme default&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On running this locally, if you see this in &lt;a href=&quot;http://localhost:8080/&quot;&gt;your browser&lt;/a&gt;, the setup is successful&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1625px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/414bd75cc017903bd9498353d28e6633/6f6d1/structurizr.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.2%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAIAAABr+ngCAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABu0lEQVR42qWSO0/CUBTH7+IncHdw0bg7uPgBjJuJu5+AMCi0KYZGjI/NRSLGRozORo3GR6yliCIMtS1oomCCEIgKIlCF0gceWkBlMBh/Offe8z/3nNwnuhTiz9l8sSjVfqKqasVAURRZlisVGSJtOUjTNBVMVUVR9Pv9FwaBQIBpcWZ0Ppbx+VoJJujmIUOLmdRrZW11xWq1YhhmN8BM8LrheEPZf4IKJekl96aomtfrdTgcLpdrpmNQUZLyhdL7R9m9vGyxWGw221THoCAXDd8mb2KPAs+d0jTLsn6W9TVhmIa1STOCotGowPPxWKxxyXqtCq0zkDnoui5XFXDmN+nRScqIaYnsx8xeYv4guXiYTOfLkLUVfCJ3EuRuYp/PgkRQZryqBj3DxbtHnF3D9tkNGuRV/G1g+npoThx0CZFUCbImqPt+B9dHcMT249fKZvFJ6K53fKFnbM65dgIylSsvHSdXmPR64CknVSFyFHl1n6XdTOb8vvBt2/WN602/9rczA5FI/YcFg5fh0NU1wJsI4HGGEASB4+s+mDmLWgt6PB54OvgnBEHgTTD8N76KKYoCTZKks2P+VfwJtBia0n2nSFwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;structurizr&quot;
        title=&quot;&quot;
        src=&quot;/static/414bd75cc017903bd9498353d28e6633/6f6d1/structurizr.png&quot;
        srcset=&quot;/static/414bd75cc017903bd9498353d28e6633/0eb09/structurizr.png 500w,
/static/414bd75cc017903bd9498353d28e6633/1263b/structurizr.png 1000w,
/static/414bd75cc017903bd9498353d28e6633/6f6d1/structurizr.png 1625w&quot;
        sizes=&quot;(max-width: 1625px) 100vw, 1625px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Visual Studio + Visual Studio Look Parity]]></title><description><![CDATA[Photo by Riku Lu on Unsplash If you cannot escape the reality of having to dance between using Visual Studio and Visual Studio Code, but…]]></description><link>http://www.drunkonmonads.com/vscode-vs-swap/</link><guid isPermaLink="false">http://www.drunkonmonads.com/vscode-vs-swap/</guid><pubDate>Sat, 24 Aug 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@riku?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Riku Lu&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/black-flat-screen-computer-monitor-wvJuYrM5iuw?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you cannot escape the reality of having to dance between using Visual Studio and Visual Studio Code, but really appreciate consistency you may  find &lt;a href=&quot;https://github.com/microsoft/theme-converter-for-vs&quot;&gt;Theme Converter for Visual Studio &lt;/a&gt;)interesting.&lt;/p&gt;
&lt;p&gt;This extension allows you to identify a theme you like in Visual Studio Code (&lt;a href=&quot;https://vscodethemes.com/&quot;&gt;great options available&lt;/a&gt; and export it for usage in Visual Studio.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1722px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9a2788a3a463d52ce7e0422490047c93/36cec/a.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 80.19999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAAAsTAAALEwEAmpwYAAACdklEQVR42n1TuW4UQRTcX0CAsXZnpu/uuc9FckRAgIyNCAhIvDYh//8FRXXPXiCZoNR3ddU7NtPHO+yXBcMwrhhH9P2AcZwwzwuWZY/9fkWcx/2IruvRtl3am6cF0zin+xujFUJZoekGXhhQlmWCtxbGGFiOinfiXEqJohAJQsSxSBCK5yFgmiZs4oFyJSx/s30L6S1c1SC0PZSx6wOxEkgprubyQsi1dpbKxxNhDd8vaPZ3KPsZtmzOZEWeX3Ak+Bc5zyKSwrgRCW0zknSA63uqraFKn9RK76DqEtLZVwlPSISK/h0VubKFrRi7nnOO1TAhNC0KwctSnJX8j3CeZ2xiXJSWcKGGtgHSOBgfYEMF4wLPDO07nq24trh+kP9t+ZStUPcM7ImwYhzrhLhnSO6qNq2lVBCE5EdSa0i1rs+WT9mzFUlaz9g5qivTYxdJ45xnvo5h4R2qdFWdKiEmT1t/Vp4II5mUBR9KhM5QnaIqTZssB51TQUHEMaMSjrpIY7bbJuRZhny3S4TDMKxJiaRlV5MwoKTKmgmxLFRtDWuM58ococ9IsdXrnjjWZNd1R8uEob1Y7SXLJVmLln1Ie57Zjoj70bpvmmQ5hsSwKWLSCnJcEdJyxRbs2W6BbeQlFdI67Ssrk21lxNH+Oi9EnuyesnylUCbJoXGoRqprHTzbUHtaMxJZHsvkFRQXJIVsis325j22N28ZD81fMli9hXcxThKKv4tse+nd2MccUz/LNVSC6ra3H3D77g3aymMzPn7H+PiC9v4Jzf0B0+Mz5wf4LweEhCe0X58xffvFewe0n3+gfXhBRwx81z+8pPsd33/6+Rt/ABMezPw6rP8JAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;a&quot;
        title=&quot;&quot;
        src=&quot;/static/9a2788a3a463d52ce7e0422490047c93/36cec/a.png&quot;
        srcset=&quot;/static/9a2788a3a463d52ce7e0422490047c93/0eb09/a.png 500w,
/static/9a2788a3a463d52ce7e0422490047c93/1263b/a.png 1000w,
/static/9a2788a3a463d52ce7e0422490047c93/36cec/a.png 1722w&quot;
        sizes=&quot;(max-width: 1722px) 100vw, 1722px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1718px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/910e5a537191dfb4b9a822ea668906c0/954d4/b.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 80.19999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAAAsTAAALEwEAmpwYAAACwElEQVR42n1Uy27bMBB0A9RFmkMSIAiQ2npRIilST9vxC0nstM2HtP2HIj/WS9GPm85SdppcehiQksjdmdldjeqmQ1O3KIxDoTW6rkfTtHzXYD5foG1bVFWNsiyhtQ177yueNTDG8p2BUjlUlkMXGqP9/iseHp6wXN9jtdzwcMNLDfp+jtnslgnmAXXdwVqPtpkxYY/S1XBOElWwxqMhka6fYVQUCoV18Dw0n8/gq4pBfWCUpgmSJCaSA4Z9mqaI4zhA3sl6cXGBKIow0gXpUq5lwNXyFjNm8c4jy7JwUSkV9scAgiiKXwVMMJ1OcXJyguvrawakb4WhPxVlkF3dd6iaBm3XwpaWPhnIGcn+OuhLwDjClN/ej8e4ubkZAhpbIqc/uWuQ03DfONSth3UmmO74zvmB9VGyIEmIlOyJs7MzTCafGJCVyskwp2zT1ARZdj7A1SWsBGvJnlXXRgdvxWNhnrPqxtdB4Xj8AZeXlxjJh9JaFiZDNTdc6WlB/1SCLE+RHdY0S6ByeZ8epB4QPIzwjh6en58zoASTHiwdSnrXLzo4Vtuy38QOy+wlv1kmtpYMBY79x85I2Xe5KaDI9PT0I66urgaG0qBK5zA1ZRjFqit6WnCfMxkblpeKsFcMlA8dIH4evCwY42H3JfTuUBQtmTL4GVlU9KWipy4NsqW6UTQNq1QzkqqyTSIilmeukuDx8YmDsBgk69LTuzIY3Hbs/pZyWQwdRktzIlhxnitL+l3qsGraoMgs1TJ2CjJxfb+QSSmGzk/EbLKSiZAJOcgRCIMB6QsGyWwZnpfmfxNQJMSUEiRE/9b/gnemk0m4ewwYJIuk180akKRvn1/hONdCRBp+YK74g/nMnwh/DrvdHtvNFuv1GtvtBpvNJuyPOD7LKri7u8discDz80/8+v0H377/wHq1wuN+h9vlAn8BEK3O7zAuoeMAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;b&quot;
        title=&quot;&quot;
        src=&quot;/static/910e5a537191dfb4b9a822ea668906c0/954d4/b.png&quot;
        srcset=&quot;/static/910e5a537191dfb4b9a822ea668906c0/0eb09/b.png 500w,
/static/910e5a537191dfb4b9a822ea668906c0/1263b/b.png 1000w,
/static/910e5a537191dfb4b9a822ea668906c0/954d4/b.png 1718w&quot;
        sizes=&quot;(max-width: 1718px) 100vw, 1718px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;There are other investments that can be made to make them more consistent. Small things go a long way like having the editor bar on the same side in both, having the font style, sizing and spacing be the same, choice of mini map etc.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Upgrading Angular]]></title><description><![CDATA[Photo by Tudor Baciu on Unsplash Upgrading Angular - Lessons from a 13 to 18 move This guide highlights some steps for consideration when…]]></description><link>http://www.drunkonmonads.com/upgrading-angular/</link><guid isPermaLink="false">http://www.drunkonmonads.com/upgrading-angular/</guid><pubDate>Sat, 13 Jul 2024 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@baciutudor?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Tudor Baciu&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/flat-screen-monitor-and-black-ceramic-mug-vc3iVL_znJ8?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Upgrading Angular - Lessons from a 13 to 18 move&lt;/h1&gt;
&lt;p&gt;This guide highlights some steps for consideration when upgrading the version of Angular you are using. This is based mainly on my experience of upgrading a project from Angular 13 to Angular 18. All the steps and options listed below have been applied for that upgrade. However, proceed with caution, all those changes required extensive research to understand the implications of the change fully and this was backed by cumbersome developer testing and a plan for a full test regression cycle before a production release.&lt;/p&gt;
&lt;p&gt;The time will come to upgrade your Angular version. It is best to not lag too far behind as it becomes a bigger chore to eventually catch up, especially if you are now forced to do it due to the need for new features or packages that are only available for a later version of Angular.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ There are multiple steps to go through for these upgrades. Make sure to do a step at a time, build and test, and address any issues, before moving on to the next step. Doing a big bang is a shortcut way to failing the whole upgrade and eventually ditching it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Do not do the upgrades by hand, but instead make use of the official update tools, using the tool available &lt;a href=&quot;https://angular.dev/update-guide&quot;&gt;here&lt;/a&gt;. The tool allows you to choose the from and to version and provides a guide. If you are upgrading across multiple versions, I would recommend doing it one version at a time fully testing things and addressing any issues before progressing to the next version. Make sure to go through and tick other dependencies like Angular Material and whether or not you are on Windows.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is best to select the Advanced application complexity in the tool so it gives you detailed guides on what to look out for and you can just ignore what is not relevant in your case. If not sure, do a code search for the mentioned components or APIs that should be updated.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The process boils down to running the command &lt;code class=&quot;language-text&quot;&gt;ng update @angular/core@xx @angular/cli@xx&lt;/code&gt; for the target version and going through the rest of the guide for any manual changes that are required. If you are working with material you will also be asked to run the command &lt;code class=&quot;language-text&quot;&gt;ng update @angular/material@xx&lt;/code&gt;. The tool will make any required changes to your &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; file and install the packages. This includes core angular dependencies, angular tooling and dependencies like TypeScript.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Make sure you have no pending changes in GIT before running the commands and commit after each step.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Check the node compatibility for the version of Angular you are targeting as you may also need to upgrade that. I highly recommend you make use of &lt;a href=&quot;https://github.com/nvm-sh/nvm&quot;&gt;nvm&lt;/a&gt;, so you can work with multiple versions of node on your machine, especially if you work across multiple projects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Breaking changes&lt;/h2&gt;
&lt;p&gt;You may encounter breaking changes, depending on your project. Here are some examples of things I ran into while upgrading from Angular 13 to 18.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Angular 15 requires form models to now have a generic type parameter. You can still opt out by using the untyped version of the form modal classes.&lt;/li&gt;
&lt;li&gt;Some dependencies, &lt;code class=&quot;language-text&quot;&gt;rxjs&lt;/code&gt; being one you will likely run into and particularly component libraries, will have versions that support specific Angular versions so as you update Angular you will have to bump some of these up too.&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;language-text&quot;&gt;package-lock.json&lt;/code&gt; file can get corrupted and track incorrect information. If your &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; starts to fail oddly or complain about packages missing that are in the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; file, it may be best to manually delete the &lt;code class=&quot;language-text&quot;&gt;package-lock.json&lt;/code&gt; file and run &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; again. If this does not work, delete the &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; folder, run &lt;code class=&quot;language-text&quot;&gt;npm cache clean --force&lt;/code&gt; then &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Angular 16 drops the &lt;code class=&quot;language-text&quot;&gt;entryComponents&lt;/code&gt; option in modules.&lt;/li&gt;
&lt;li&gt;Angular 18 does not accept certain special characters in string literals in HTML templates, like the &lt;code class=&quot;language-text&quot;&gt;@&lt;/code&gt; character which I had to replace with &lt;code class=&quot;language-text&quot;&gt;&amp;amp;#64;&lt;/code&gt;. The failing build was very clear about this issue and made a change recommendation.&lt;/li&gt;
&lt;li&gt;When updating material there is a chance that some of the look and feel in your application may change and some weird UI bugs may also pop up, for example, controls no longer being positioned properly. Make sure to fully test things.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are just examples of some breaking changes you can encounter. The good news is that any Angular-related changes I ran into were already mentioned in the upgrade tool with recommendations.&lt;/p&gt;
&lt;p&gt;I am quite pleasantly surprised at how useful the Angular upgrade tool is and how much it automates, combined with how well the build gives detailed errors for anything that needs attention. While these upgrades remain quite tedious and very demanding in terms of testing, the tooling did make this significantly better.&lt;/p&gt;
&lt;h1&gt;New Angular, now what?&lt;/h1&gt;
&lt;p&gt;Now you have the new Angular and all the new features at your fingertips and any of the benefits like improved build and run times etc. One beast you may want to confront already is that over time you may start to have inconsistencies in your project. For instance if you now suddenly have access to the new standalone components, do you now only use them going forward and retain the modules you already have?&lt;/p&gt;
&lt;p&gt;That is a tough question and the answer may largely depend on how complex your project is and how bold you are feeling. I would however recommend migrating as much as you can to use new features if you are already going to invest in tons of regression testing.&lt;/p&gt;
&lt;h3&gt;Migrate to use standalone components&lt;/h3&gt;
&lt;p&gt;You can migrate to use the standalone components using the official tooling &lt;code class=&quot;language-text&quot;&gt;ng generate @angular/core:standalone&lt;/code&gt;, see more documentation &lt;a href=&quot;https://angular.dev/reference/migrations/standalone&quot;&gt;here&lt;/a&gt;. This will migrate in 3 steps&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Convert all components, directives and pipes to standalone&lt;/li&gt;
&lt;li&gt;Remove redundant NgModule classes&lt;/li&gt;
&lt;li&gt;Bootstrap the application using standalone APIs&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;I highly recommend biting the bullet and doing this one as this highly reduces boilerplate code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;When I did this I had to address a few things manually. Suddenly some components that were using &lt;code class=&quot;language-text&quot;&gt;app-sidebar&lt;/code&gt; that does not exist with Angular 18 only started to fail the build after this move. A manual step we have to pull app configuration was also not migrated well and only done for the app root, but not for child components that required it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Migrate the material theme&lt;/h2&gt;
&lt;p&gt;If you are working with material and have updated across Angular material versions that also have an update to the material specification, for example from the material specification 2 to 3, you may need to update your base theme if you are using any, as those target a specific specification, documentation &lt;a href=&quot;https://material.angular.io/guide/theming&quot;&gt;here&lt;/a&gt;. In our scenario we had the deeppurple-amber.css as the base and we chose to move over to azure-blue.css.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1018px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/bc92088d6adc15fd63827f65f9845274/f759a/one.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 69.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABl0lEQVR42oVS7XarMAzr+z/oNkoI+SYkoZqcll2gO3c/dEjkWDaybyU3eBOwVeDR3tHKBm8jHN/IW2zk1g1uDh0Sl9wdt5gyhlHDxwWB5ytcSPgaJwxKw/IclxXWR3zeVYcNEYUFWnk8BbUPuOsZ42SgjftVUGmDlMuJE7GBhT5G1YuImIjecq6YbYAhQsxYeD8iphWz8RcuY1Qz1DQz16OWQ4dyWEJGiivqevZDIFxi/MqJp+J98rmL/QhKMPpE4wO/C7ZXcMe6VASXTlwhZ7TrOMaegjJFCkV2IVjXhibTfUHuwh+5whzD7iwRwrVDVvBfCknRePqSWbVJ1ReK/NY4v3H2c4Qj4qDR2HETO2QoVVs4CnplESgaKVilKj0VFHbvye/3zlHUDBPMXSNQtMn7H0E+CAz0DieLyiVuFNlReA/S4YWTJgRRYlz4f1OuDzhWFC8SV+To1e5X+MvDepmyTMpy1+QrU/1zyvl/U+5rs3Sk8NzFc3Lre3jlZA8Fkvcm6F3slST4m+AxaeeM9rAz/8qfO/wGacdCCF2DXM8AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;one&quot;
        title=&quot;&quot;
        src=&quot;/static/bc92088d6adc15fd63827f65f9845274/f759a/one.png&quot;
        srcset=&quot;/static/bc92088d6adc15fd63827f65f9845274/0eb09/one.png 500w,
/static/bc92088d6adc15fd63827f65f9845274/1263b/one.png 1000w,
/static/bc92088d6adc15fd63827f65f9845274/f759a/one.png 1018w&quot;
        sizes=&quot;(max-width: 1018px) 100vw, 1018px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Migrate control flow syntax&lt;/h3&gt;
&lt;p&gt;You can migrate to the new and shiny &lt;a href=&quot;https://angular.dev/guide/templates/control-flow&quot;&gt;control flow syntax&lt;/a&gt; available since Angular 17 that simplifies the use of directives like &lt;code class=&quot;language-text&quot;&gt;*ngFor&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;*ngIf&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;*ngSwitch&lt;/code&gt;. This can be run using the official tooling &lt;code class=&quot;language-text&quot;&gt;ng generate @angular/core:control-flow&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Other migrations&lt;/h3&gt;
&lt;p&gt;There are other migrations that you may be interested in that have tooling support or are fully documented. See the available migrations &lt;a href=&quot;https://angular.dev/reference/migrations&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;angular.json&lt;/h3&gt;
&lt;p&gt;Depending on the version update you may also want to make changes to your &lt;code class=&quot;language-text&quot;&gt;angular.json&lt;/code&gt; config file.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;browserTarget&lt;/code&gt; is dropped for &lt;code class=&quot;language-text&quot;&gt;buildTarget&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;defaultProject&lt;/code&gt; is now obsolete&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;defaultCollection&lt;/code&gt; is now obsolete&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;You can find out what needs to be changed by opening the file in your IDE to see any warnings. Comparing what you have with the default that is generated for a new project on the same Angular version is also a good idea.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;tsconfig.json&lt;/h3&gt;
&lt;p&gt;Given that the version of TypeScript would have been updated, you should also look to see what configuration can be updated in the &lt;code class=&quot;language-text&quot;&gt;tsconfig.json&lt;/code&gt; file&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consider newer settings like
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/tsconfig/#noPropertyAccessFromIndexSignature&quot;&gt;noPropertyAccessFromIndexSignature&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/tsconfig/#noImplicitOverride&quot;&gt;noImplicitOverride&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/tsconfig/#esModuleInterop&quot;&gt;esModuleInterop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/tsconfig/#skipLibCheck&quot;&gt;skipLibCheck&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.typescriptlang.org/tsconfig/#moduleResolution&quot;&gt;moduleResolution&lt;/a&gt; move from &lt;code class=&quot;language-text&quot;&gt;node&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;bundler&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;bumping up the ECMAScript version under &lt;code class=&quot;language-text&quot;&gt;target&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;module&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;lib&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Other dependencies&lt;/h1&gt;
&lt;p&gt;This is a good time to look into upgrading all other dependencies, and in particular, some dependencies will be tied to a particular version of Angular, Node or TypeScript, which would also likely have changed.&lt;/p&gt;
&lt;p&gt;Make sure to read the official documentation of each package to see what has changed and check the compatibility information. If you are far behind you are very likely to meet many packages with API changes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Update packages one at a time making sure to build and test your project afterwards. A big bang update and then having issues is a nice way to get bogged fail here.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Consider making use of the command &lt;code class=&quot;language-text&quot;&gt;npm outdated&lt;/code&gt; to track packages that need updates through a convenient report.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 498px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/cce2ec6f575b5ae5f375053a08d15683/c365b/two.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 50.20080321285141%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsSAAALEgHS3X78AAABq0lEQVR42kWRaW7cMAyFfZaiTSZje7RZIrXaknd7FjTBFLn/SaqZIC1ACNSPj4/vsTDd5tNFubExfUnwtRSvVZPfiqLU8cQNEU5iLAlwCKSxNTdctfn7cuTF1fW/u3mSxhNVE5mLUnkoOVPtuL6jGWQIYZ0Is5O/W1hC3Of93g03ZVKxe9idOnt9C+Yc9K3TSQOh8teRaz9KSKUQIsKJoSM7ktGGJY7XYXlv014kh4PDaMAqZaQyCpRQDZeHSirbMxkqoXiLlFrPL8hGsL1tF9ttuSk+0H1q94kOKfwom0P1qOxZYOyGC5hedAiLUU0cxN3x1cct25n3P11/LlZqN2oWYhLVcIK3b/gkbFbIUVEDsteMW8/OSMc87qHcrg/lXZkL2FWagerMe4K0Vi+lKCl+wTUonGxFVeBXz1bXLmm8DctHiFsxCT02WhD183mkr7XzGWjjfVwFBOZQjabmmGHDJu2ntr90w9WGqUgSJ6lnpXNOh+q/5+qpLKAjGmQ0NQPDNsvmDIe0P+G5aDUMFpNFzuQ/5e/MOtb4I2uYxSORDUmafXnOse3ohr9rJYbIjxcZCAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;two&quot;
        title=&quot;&quot;
        src=&quot;/static/cce2ec6f575b5ae5f375053a08d15683/c365b/two.png&quot;
        srcset=&quot;/static/cce2ec6f575b5ae5f375053a08d15683/c365b/two.png 498w&quot;
        sizes=&quot;(max-width: 498px) 100vw, 498px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Also, consider making use of the VS Code extension, &lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=pflannery.vscode-versionlens&quot;&gt;Version Lens&lt;/a&gt; for convenient information directly in your &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; file with upgrade actions directly from there.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 407px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e43980b8dd46b6cbc05e122e60c46ab1/fc7bc/three.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 53.07125307125307%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAIAAADwazoUAAAACXBIWXMAAAsSAAALEgHS3X78AAABDklEQVR42sWQW27CMBBFsxMIwfHM+AEhThzb5AGE0pD976cOrfioBP2sdGVZmnOs8U0ul3aar+Ptch67ui7csW5D44OJl8aVxR45X3Oefgdg0/iya6w1e6VYojXWBiIkaUs8JUgFZPGUIheCIW6e5o+PG4SYLD6UAGaKVljuMHjyVjgbT2wqOGgpeITyfP3LfyZBzIgY7YUcRz3P+j6p/qht6Y6Vd8ba4pW5yERbKVncRN4+1TSpoZd9q7pwONAw+NMphGAi80LGrZAsjqlr1X1WQyc/rtK7nQbny35wVaVfbZ4IYlIxU+ilDGIAGceMP2iApV7+/s+mzIkexeSrBWVPev2mrUV+M/sz/yd/Aeaua8CqW7x+AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;three&quot;
        title=&quot;&quot;
        src=&quot;/static/e43980b8dd46b6cbc05e122e60c46ab1/fc7bc/three.png&quot;
        srcset=&quot;/static/e43980b8dd46b6cbc05e122e60c46ab1/fc7bc/three.png 407w&quot;
        sizes=&quot;(max-width: 407px) 100vw, 407px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Specific dependencies you may want to immediately update if you depend on are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rxjs&lt;/li&gt;
&lt;li&gt;component libraries, i.e. ngx-bootstrap&lt;/li&gt;
&lt;li&gt;eslint&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hopefully you can update all packages and get to see this nice report on &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 535px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d8773156a5d731af400ab504a50f24ae/b5bcd/four.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 30.599999999999998%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsSAAALEgHS3X78AAAA90lEQVR42k1Qi26EIBDkPxSvPmp6ESyCQgWEO6mv+v//01UvTSfZzc5md3YAVYRaa4QQnVTbtjUNq+vPbV3Hcey11kav26q+1PPEvu9KSc65lIrzBqVpmud5HMc4xkmSQAEZ46O+iujs3A68AZLbawY4IrQO30FKOU0TaMNxEHbOtULA5WmevPdSqWEYGGPO+fU0db9/gASCIISOIRBC5mUJYdTGzstMKfWPR9u2P/sOurBcliXcBqdFUUAGU+hyCB7AX5ZlOHnRKIqOJsaQ0wyG04sCjjeeW6iqqt4Y2+v3npWMGPBqemutd052HTDBOcz//cJ//AINHz/A3f5uZgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;four&quot;
        title=&quot;&quot;
        src=&quot;/static/d8773156a5d731af400ab504a50f24ae/b5bcd/four.png&quot;
        srcset=&quot;/static/d8773156a5d731af400ab504a50f24ae/0eb09/four.png 500w,
/static/d8773156a5d731af400ab504a50f24ae/b5bcd/four.png 535w&quot;
        sizes=&quot;(max-width: 535px) 100vw, 535px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Cleanup&lt;/h2&gt;
&lt;p&gt;We took the Angular upgrade as an opportunity to identify and clean up any unused packages. That is a little less to worry about upgrading and this can also help keep bundle sizes reasonable.&lt;/p&gt;
&lt;p&gt;Unused packages are not as simple as checking the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; and finding something that is not used at all. Some may be used in modules/components that are not used in your project which would mean also deleting those artefacts.&lt;/p&gt;
&lt;h1&gt;Package.json&lt;/h1&gt;
&lt;p&gt;Make sure the common CLI tasks that developers run are available as scripts in the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; file. Examples are serving, building, testing and linting.&lt;/p&gt;
&lt;p&gt;Add an engines section so that the team knows and has a reference point for the supported runtimes like node. Example&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;engines&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;node&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;20.15.1&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;npm&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;10.7.0&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Make sure no dependencies that should be for development only are in the main dependencies list.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Package-lock.json&lt;/h2&gt;
&lt;p&gt;When making multiple changes and in particular when the version of node has been updated, the &lt;code class=&quot;language-text&quot;&gt;package-lock.json&lt;/code&gt; can at times get corrupted and have incorrect information. It is a good idea to delete the file once done with the upgrade and run &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; again to have the file re-populated.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you manage to update all dependencies, great. If not, it is still worth running an audit fix with &lt;code class=&quot;language-text&quot;&gt;npm run audit --fix&lt;/code&gt; to attempt to address packages with known vulnerabilities.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Testing&lt;/h1&gt;
&lt;p&gt;I would not recommend investing time in component testing with Angular. Writing unit tests for algorithm type code for example if you have a function that applies some formatting on numbers, that is something you may want to write unit tests for. For this, I recommend bootstrapping &lt;a href=&quot;https://jestjs.io/&quot;&gt;Jest&lt;/a&gt; onto your project.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;When using jest for tests, keep in mind that jest runs on node and not in a browser, so any code that makes use of browser APIs that you would like to test would require mocks. Local storage is an example of an API that is implemented by browsers and not by node.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you are not going to be writing component tests, it is best to remove all the dependencies for that (one less thing to worry about and keep up to date). Some dependencies to drop are jasmine, and karma including configuration files (&lt;code class=&quot;language-text&quot;&gt;karma.conf.js&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;tsconfig.spec.json&lt;/code&gt; etc) and any specs you may have already generated (&lt;code class=&quot;language-text&quot;&gt;*.spec.ts&lt;/code&gt;). Make sure to also remove the test configuration in your &lt;code class=&quot;language-text&quot;&gt;angular.json&lt;/code&gt; file.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you are making use of the ng generate command make sure to use the &lt;code class=&quot;language-text&quot;&gt;--skip-tests&lt;/code&gt; flag if you are not making use of component tests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Node version&lt;/h1&gt;
&lt;p&gt;As part of the upgrade do not forget to update your version of node. Make sure that you are working with a supported version of Node both locally and for your deployments. Check &lt;a href=&quot;https://angular.dev/reference/versions&quot;&gt;the official compatibility matrix&lt;/a&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Do not run on an unsupported version of node. It may work now until you run into very weird bugs in the future. In those situations, you may not figure out that it is due to the node version and even if you do, now what? Bump down and regression test everything? Best to just avoid this. Also, make sure that the version of node used in production is the same one used by developers on their machines.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;A good reason to upgrade Angular regularly is to keep up with an LTS version of Node. Node does however have very long maintenance windows. Check the official documentation &lt;a href=&quot;https://nodejs.org/en/about/previous-releases&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Scenic route&lt;/h1&gt;
&lt;p&gt;If you are making such a big change, this will no doubt be backed up by a regression test cycle. This is an opportunity to address any other low hanging-fruit.&lt;/p&gt;
&lt;h2&gt;Imports&lt;/h2&gt;
&lt;p&gt;Does your project have a lot of imports that walk up and down the folder tree like &lt;code class=&quot;language-text&quot;&gt;../../../..&lt;/code&gt;. These paths are not great as they tend to be long and do not do very well with moving files around, although most IDEs can handle this.&lt;/p&gt;
&lt;p&gt;This is a nice time to address this by identifying the most commonly imported items in your project and creating aliases for those in your &lt;code class=&quot;language-text&quot;&gt;tsconfig.json&lt;/code&gt; allowing us to simply something like &lt;code class=&quot;language-text&quot;&gt;../../../components/..&lt;/code&gt; to &lt;code class=&quot;language-text&quot;&gt;@components/..&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Here is a sample configuration, this will differ depending on your folder structure.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;compilerOptions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;paths&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;@services/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;src/services/*&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;@models/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;src/models/*&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;@environments/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;src/environments/*&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;@store/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;src/app/store/*&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;@modules/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;src/app/modules/*&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      ],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;@shared/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;src/app/modules/shared/*&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;IDEs like VS Code will be aware of this configuration and will take this into account for auto imports.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Jest does not pull this information, so if you using Jest you will need to create module name mappings in the &lt;code class=&quot;language-text&quot;&gt;jest.config.js&lt;/code&gt;, example&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;module.exports = {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;preset&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;ts-jest&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;testEnvironment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;node&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;moduleNameMapper&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;^@services/(.*)$&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&amp;lt;rootDir&amp;gt;/src/services/$&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;^@models/(.*)$&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&amp;lt;rootDir&amp;gt;/src/models/$&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;^@environments/(.*)$&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&amp;lt;rootDir&amp;gt;/src/environments/$&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;^@store/(.*)$&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&amp;lt;rootDir&amp;gt;/src/app/store/$&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;^@modules/(.*)$&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&amp;lt;rootDir&amp;gt;/src/app/modules/$&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;^@shared/(.*)$&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&amp;lt;rootDir&amp;gt;/src/app/modules/shared/$&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Warnings&lt;/h2&gt;
&lt;p&gt;Look out for warnings that would be easy to address&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build warnings&lt;/li&gt;
&lt;li&gt;Lint warnings&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; warnings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some examples of things that may be shown as warnings after an upgrade&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ambiguous CSS when working with flex layouts, for example, &lt;code class=&quot;language-text&quot;&gt;start&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;end&lt;/code&gt; as opposed to &lt;code class=&quot;language-text&quot;&gt;flex-start&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;flex-end&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Unsupported engines on doing &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt; will warn you about the version of node being a mismatch to some packages&lt;/li&gt;
&lt;li&gt;While not specific to the upgrade, it could be good to also address any vulnerabilities flagged by &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt;. Consider updating all your packages and where that is not possible consider running &lt;code class=&quot;language-text&quot;&gt;npm audit --fix&lt;/code&gt; to patch what would likely not result in breaking changes.&lt;/li&gt;
&lt;li&gt;Angular will warn of the use of any CommonJS or AMD dependencies that can cause optimization bailouts and larger than necessary bundles. Angular can better do optimization during builds when working with ECMAScript modules. This warning will likely be due to dependencies and one common library that causes this is Lodash. In this case, it comes with &lt;code class=&quot;language-text&quot;&gt;lodas-es&lt;/code&gt;, that you can replace with to address this.&lt;/li&gt;
&lt;li&gt;Due to updating TypeScript, you may start to see new warnings depending on what you have in your project.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the example above of &lt;code class=&quot;language-text&quot;&gt;lodash&lt;/code&gt; warnings, make sure to update the core and types packages to use &lt;code class=&quot;language-text&quot;&gt;lodash-es&lt;/code&gt; and update all imports for example, &lt;code class=&quot;language-text&quot;&gt;import { isEmpty } from &apos;lodash&apos;;&lt;/code&gt; becomes &lt;code class=&quot;language-text&quot;&gt;import { isEmpty } from &apos;lodash-es&apos;;&lt;/code&gt;. If you are making use of jest, you will need to provide a module name mapper in your &lt;code class=&quot;language-text&quot;&gt;jest.config.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;/** @type {import(&amp;#39;tsjest&amp;#39;).JestConfigWithTsJest} */&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;module.exports = {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;preset&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;ts-jest&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;testEnvironment&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;node&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;moduleNameMapper&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;^lodash-es$&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;&amp;#39;lodash&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Linting&lt;/h2&gt;
&lt;p&gt;If you are modernizing your Angular SPA project, if you are not already working with eslint, I would highly recommend it and if you already are, this is also a good time to review your linting rules. If you are able to, upgrade to the highest eslint version that is supported for the version of Angular you have targeted.&lt;/p&gt;
&lt;p&gt;Here is a simple configuration as an example for the latest eslint that now makes use of eslint.config.js.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;node:path&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fileURLToPath&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;node:url&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;eslint&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;@eslint/js&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FlatCompat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;@eslint/eslintrc&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__filename&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;fileURLToPath&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;meta&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__dirname&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;dirname&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__filename&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;compat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FlatCompat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;baseDirectory:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__dirname&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;recommendedConfig:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;eslint&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;recommended&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;allConfig:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;eslint&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;all&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ignores:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;projects/**/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;coverage/**/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;**/generated.ts&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}, ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;compat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;plugin:@angular-eslint/recommended&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;plugin:@angular-eslint/template/process-inline-templates&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;files:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;**/*.ts&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;})), {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;files:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;**/*.ts&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;linterOptions:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;reportUnusedDisableDirectives:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;off&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;languageOptions:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ecmaVersion:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sourceType:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;script&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;parserOptions:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;project:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;tsconfig.json&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;createDefaultProgram:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;rules:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;@angular-eslint/use-lifecycle-interface&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;@angular-eslint/no-empty-lifecycle-method&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;off&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;@angular-eslint/directive-selector&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;off&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;@angular-eslint/component-selector&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;off&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;@angular-eslint/no-output-on-prefix&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;off&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;no-unused-vars&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;vars:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;all&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;args:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;none&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ignoreRestSiblings:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;no-console&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;no-alert&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;no-debugger&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;error&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}, ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;compat&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;plugin:@angular-eslint/template/recommended&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;files:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;**/*.html&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;})), {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;files:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;**/*.html&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;rules:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {},&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;If you have a linting setup, make sure that your commands (ideally scripts in the &lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; file pass the &lt;code class=&quot;language-text&quot;&gt;--cache&lt;/code&gt; flag for faster runs). This will ensure that the linter only runs on files that have changed since the last run. Make sure to ignore the caching file from GIT.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;If you have a linting setup, I highly recommend making use of &lt;a href=&quot;https://github.com/lint-staged/lint-staged&quot;&gt;lint-staged&lt;/a&gt;, to allow developers to run linting only for files that they have changed and are staged in GIT.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Keep your linting clean. Having tons of warnings that no one ever looks into is a nice way to slowly get the team to not care about linting. Either address all warnings, ignore existing warnings that are too difficult/risky to address or a combination of both.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Other cleanups&lt;/h2&gt;
&lt;p&gt;Also, consider other cleanups&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Remove any unused static assets to keep your bundles small.&lt;/li&gt;
&lt;li&gt;Consider your &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; as well as your npm cache a mess right now and delete the folder, run &lt;code class=&quot;language-text&quot;&gt;npm cache clean --force&lt;/code&gt; and then &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk14 { color: #F44747; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Linting in .NET]]></title><description><![CDATA[Photo by Tim Gouw on Unsplash Linting in .NET Utilizing Roslyn analyzers for linting in .NET projects offers a myriad of advantages that can…]]></description><link>http://www.drunkonmonads.com/linting-dot-net/</link><guid isPermaLink="false">http://www.drunkonmonads.com/linting-dot-net/</guid><pubDate>Mon, 03 Jun 2024 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@punttim?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Tim Gouw&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/red-light-of-traffic-light-_U-x3_FYxfI?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Linting in .NET&lt;/h1&gt;
&lt;p&gt;Utilizing Roslyn analyzers for linting in .NET projects offers a myriad of advantages that can significantly enhance code quality and developer productivity. Unlike external tools like SonarQube (which are great btw, and can also be used in combo with Roslyn), Roslyn analyzers provide a seamless integration directly into IDEs and the dotnet CLI, empowering developers to identify and rectify issues in real-time as they write code. This immediate feedback loop fosters a proactive approach to addressing potential bugs, adherence to coding standards, and best practices, resulting in cleaner, more maintainable codebases.&lt;/p&gt;
&lt;p&gt;Moreover, Roslyn analyzers offer deep insights into code patterns specific to .NET, enabling developers to leverage language-specific optimizations and refactoring’s effectively.&lt;/p&gt;
&lt;p&gt;Linting of projects is generally best done early as you will not be overwhelmed with many pre-existing warnings on setting it up and risk getting numb to these. For .NET solutions it is a great idea to enable the &lt;code class=&quot;language-text&quot;&gt;TreatWarningsAsErrors&lt;/code&gt; in the beginning (ideally via a &lt;code class=&quot;language-text&quot;&gt;Directory.Build.props&lt;/code&gt; file) and you are never in too deep to do it later as you can use the &lt;code class=&quot;language-text&quot;&gt;WarningsNotAsErrors&lt;/code&gt; to ignore some and possibly &lt;code class=&quot;language-text&quot;&gt;NoWarn&lt;/code&gt; to suppress some from being in your build warnings, with care however to not suppress something you wish you had seen later. You can apply these overrides globally with a &lt;code class=&quot;language-text&quot;&gt;Directory.Build.props&lt;/code&gt; file or per project. You can also suppress things inline, although this is only useful when you have only a hand full of things to suppress. Example&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;#pragma warning disable [Rule Code] &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// short comment explaining what is ignored&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cfg&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;UseRetry&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;#pragma warning restore [Rule Code] &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;//&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If &lt;code class=&quot;language-text&quot;&gt;TreatWarningsAsErrors&lt;/code&gt; is too harsh for your scenario you can instead replace the combo &lt;code class=&quot;language-text&quot;&gt;TreatWarningsAsError&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;WarningsNotAsErrors&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;NoWarn&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;WarningsAsErrors&lt;/code&gt; + &lt;code class=&quot;language-text&quot;&gt;NoWarn&lt;/code&gt; to target specific things.&lt;/p&gt;
&lt;p&gt;If done well your pipeline should not be overwhelming with warnings and you IDE should reflect the same.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/linting-dotnet/a.png&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;One really great thing about Roslyn is that if the analysis rule also has a fix, this shows up in the IDE and can be done conveniently. Even when working with 3rd party Analyzers, the IDE support is impressive.
![[Pasted image 20240419171537.png]]&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/linting-dotnet/b.png&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/linting-dotnet/c.png&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once you have configured the rules and build behavior, everything just works and concisely for you IDEs, CLI, and Pipeline runs.&lt;/p&gt;
&lt;h1&gt;Analysis Rules&lt;/h1&gt;
&lt;p&gt;The default rule set is very relaxed as there are mostly not rights to some of the rules, like the ones around formatting and style, which however are important to have a consistent approach decided upfront and enforced. Out of the box this means you do not get too much from Roslyn and have to invest the upfront effort to actually configure these rules.&lt;/p&gt;
&lt;p&gt;If you do not already have analysis setup, a good starting point to is to add a new .editorconfig file using the Visual Studio Solution context menu. This will add one that reflects the way your solution code already looks. You can author the rules by hand, or double click the file which will open a visualizer in Visual Studio.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/linting-dotnet/d.png&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;Lean general rule recommendation as a starting point&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;root = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[*]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;guidelines = 120&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# All files&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[*]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;indent_style = space&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_indent_labels = one_less_than_current&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_using_directive_placement = outside_namespace:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_prefer_simple_using_statement = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_prefer_braces = true:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_namespace_declarations = file_scoped:warning&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_prefer_method_group_conversion = true:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_prefer_top_level_statements = true:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_expression_bodied_methods = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_expression_bodied_constructors = false:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_expression_bodied_operators = false:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_expression_bodied_properties = true:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_expression_bodied_indexers = true:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_expression_bodied_accessors = true:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_expression_bodied_lambdas = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_expression_bodied_local_functions = false:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_throw_expression = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_prefer_null_check_over_type_check = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_prefer_simple_default_expression = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_prefer_local_over_anonymous_function = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_prefer_index_operator = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_prefer_range_operator = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_prefer_tuple_swap = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_prefer_utf8_string_literals = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_inlined_variable_declaration = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_deconstructed_variable_declaration = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_unused_value_assignment_preference = discard_variable:warning&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_style_unused_value_expression_statement_preference = discard_variable:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;csharp_space_around_binary_operators = before_and_after&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.API1000.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.API1001.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.API1002.severity = suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# disallow async void&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.S3168.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Xml files&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[*.xml]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;indent_size = 2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[*.{cs,vb}]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;#### Naming styles ####&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Naming rules&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_rule.types_should_be_pascal_case.symbols = types&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Symbol specifications&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_symbols.interface.applicable_kinds = interface&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_symbols.interface.required_modifiers =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_symbols.types.required_modifiers =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_symbols.non_field_members.required_modifiers =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Naming styles&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.begins_with_i.required_prefix = I&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.begins_with_i.required_suffix =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.begins_with_i.word_separator =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.begins_with_i.capitalization = pascal_case&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.pascal_case.required_prefix =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.pascal_case.required_suffix =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.pascal_case.word_separator =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.pascal_case.capitalization = pascal_case&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.pascal_case.required_prefix =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.pascal_case.required_suffix =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.pascal_case.word_separator =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_naming_style.pascal_case.capitalization = pascal_case&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_operator_placement_when_wrapping = beginning_of_line&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;tab_width = 4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;indent_size = 4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;end_of_line = crlf&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_coalesce_expression = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_null_propagation = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_prefer_auto_properties = true:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_object_initializer = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_collection_initializer = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_prefer_simplified_boolean_expressions = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_prefer_conditional_expression_over_assignment = true:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_prefer_conditional_expression_over_return = true:silent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_explicit_tuple_names = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_prefer_inferred_tuple_names = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_prefer_compound_assignment = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_prefer_simplified_interpolation = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_style_namespace_match_folder = true:suggestion&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# cancellation tokens must be forwarded to methods that accept them&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.CA2016.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# cancellation tokens must come last in method signatures&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.CA1068.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My recommended rules may be rather aggressive for an existing code base, but I cannot insist more for new code bases as a good start and as a team as errors pop up you can pivot and decide on your preferences, however the rules that pick up on security, vulnerabilities and bugs are best left aggressive as those are the ones that really add value. For legacy code bases, I recommend an incremental approach where you make a wish list of most important rules and slowly eat away at this, fixing those that are low risk/easy to test right away and potentially suppressing existing scenarios that are risking to apply with haste.&lt;/p&gt;
&lt;h2&gt;3rd Party Analyzers&lt;/h2&gt;
&lt;p&gt;Here are my GOTO recommendations&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://github.com/xunit/xunit.analyzers&quot;&gt;xUnit Analyzers&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This one comes out of the box with xUnit, however it requires some investment to configure to server you.&lt;/p&gt;
&lt;p&gt;Go through the analysis rules and see what makes sense with your team.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/linting-dotnet/e.png&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;I prefer to make use of xUnit as a test framework, but not as an assertion framework and use Fluent Assertions for that.&lt;/p&gt;
&lt;p&gt;Recommended rules&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Tests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# XFA001: Use FluentAssertions equivalent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.XFA001.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit1004: Test methods should not be skipped&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit1004.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit1006: Theory methods should have parameters&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit1006.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit1008: Test data attribute should only be used on a Theory&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit1008.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit1013: Public method should be marked as test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit1013.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit1014: MemberData should use nameof operator for member name&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit1014.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit1025: InlineData should be unique within the Theory it belongs to&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit1025.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit1026: Theory methods should use all of their parameters&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit1026.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2000: Constants and literals should be the expected argument&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2000.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2003: Do not use equality check to test for null value&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2003.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2004: Do not use equality check to test for boolean conditions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2004.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2007: Do not use typeof expression to check the type&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2007.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2008: Do not use boolean check to match on regular expressions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2008.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2009: Do not use boolean check to check for substrings&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2009.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2010: Do not use boolean check to check for string equality&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2010.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2012: Do not use Enumerable.Any() to check if a value exists in a collection&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2012.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2011: Do not use empty collection check&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2011.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2013: Do not use equality check to check for collection size.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2013.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2015: Do not use typeof expression to check the exception type&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2015.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2017: Do not use Contains() to check if a value exists in a collection&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2017.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2018: Do not compare an object&amp;#39;s exact type to an abstract class or interface&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2018.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# xUnit2019: Do not use obsolete throws check to check for asynchronously thrown exception&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.xUnit2019.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;a href=&quot;https://github.com/fluentassertions/fluentassertions.analyzers&quot;&gt;Fluent Assertions Analyzer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The first thing I recommend with this is ensuring that only Fluent Assertions can be used as an assertions framework.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/linting-dotnet/f.png&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;As a bonus, if you had xUnit assertions, you can just click on any one of the new errors and use Roslyn to convert all your assertions to Fluent Assertions.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/linting-dotnet/g.png&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Replace Xunit assertion with Fluent Assertions equivalent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.MFA001.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Replace MSTests assertion with Fluent Assertions equivalent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.MFA002.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Replace NUnit assertion with Fluent Assertions equivalent&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.MFA003.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;a href=&quot;https://josefpihrt.github.io/docs/roslynator/category/guides/&quot;&gt;Roslynator&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Roslynator is a set of code analysis tools for C#, powered by &lt;a href=&quot;https://github.com/dotnet/roslyn&quot;&gt;Roslyn&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://github.com/SonarSource/sonar-dotnet&quot;&gt;Sonar Analyzer&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Saving the best for last. I think this is hands down my preferred Analyzer as it comes with really great rules and fixes, with a whooping &lt;a href=&quot;https://rules.sonarsource.com/csharp/&quot;&gt;450+ rules&lt;/a&gt;. This one works really great when used with the Sonar Lint extension available in &lt;a href=&quot;https://www.sonarsource.com/products/sonarlint/&quot;&gt;multiple IDEs&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://rules.sonarsource.com/csharp/RSPEC-4136/&quot;&gt;documentation&lt;/a&gt; of the rules from Sonar is 1st class and goes a long way in helping a team get up to speed with anything that may be new to them.&lt;/p&gt;
&lt;h3&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-format&quot;&gt;dotnet format&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This one is not really an Analyzer, but is a dotnet global tool, which comes shipped with any .NET SDK, 5 and beyond can be used to enforce formatting as well as Roslyn rules solution wide. This started off as a formatter and has grown to be more and it’s name no longer serves it justice. On running this tool preferences will be read from an .editorconfig file, if present, otherwise a default set of preferences will be used.&lt;/p&gt;
&lt;p&gt;Formatting is one of those things that can be tricky to have rigid gates on. Do you really want to block a PR due to a redundant line or additional space at the end of an expression? So some of these issues go ignored or unnoticed, but maybe once or twice a year it is good to just run this solution wide and get formatting to a clean slate before proceeding. On teams with good discipline, I have noticed that on doing this surprisingly there is quite a low number of formatting issues, biased though due to the high use of code generators which make things consistent.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Documenting individual roles and responsibilities]]></title><description><![CDATA[Photo by Pascal Swier on Unsplash Documenting individual roles and responsibilities The need for a shared understanding of individual roles…]]></description><link>http://www.drunkonmonads.com/shared-view-of-roles/</link><guid isPermaLink="false">http://www.drunkonmonads.com/shared-view-of-roles/</guid><pubDate>Thu, 26 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@pascalswier?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Pascal Swier&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/brown-foosball-table-closeup-photography-7de474KZIbs?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Documenting individual roles and responsibilities&lt;/h1&gt;
&lt;p&gt;The need for a shared understanding of individual roles and responsibilities within a team is fundamental to ensuring smooth project execution and achieving collective goals efficiently. Most teams/ogarnizations will no doubt have some mature process of clearly defining individual roles such as the RACI model. When a team gets together however this may be too detailed and complex to use as a reference point. A simple and easy to understand document that can be used as a reference point is therefore needed.&lt;/p&gt;
&lt;p&gt;I advocate for a simple summary of each role, a paragraph or so in your team’s Wiki that can be used as a reference point. This should be a living document that is updated as the team evolves and grows. The document should be easy to understand and should be written in a language that is easy to understand by all team members. The document should be easily accessible and should be linked to from other documents such as the team’s onboarding document. This will help the team with the following&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Clarity and Alignment&lt;/p&gt;
&lt;p&gt;A shared view of roles and responsibilities ensures that everyone is on the same page regarding who is responsible for what. This clarity minimizes confusion, aligns expectations, and fosters a collaborative environment&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Efficiency and Productivity&lt;/p&gt;
&lt;p&gt;When each team member understands their role and the roles of others, it streamlines work processes, reduces redundancy, and enhances productivity.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Accountability&lt;/p&gt;
&lt;p&gt;Documenting roles and responsibilities provides a reference point for accountability. It’s clear who is responsible for each task or deliverable, promoting a culture of ownership and accountability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Onboarding and Training&lt;/p&gt;
&lt;p&gt;Having a succinct documentation of roles and responsibilities is invaluable for onboarding new team members. It accelerates the learning curve, enabling newcomers to quickly understand the team structure and their role within it.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Communication&lt;/p&gt;
&lt;p&gt;Effective communication is facilitated when everyone knows who to go to for what. It enhances the decision-making process and ensures that information flows to the right places.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Conflict Resolution&lt;/p&gt;
&lt;p&gt;In case of conflicts or misunderstandings, having a documented reference helps in resolving issues objectively and swiftly.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Example&lt;/h2&gt;
&lt;h3&gt;ACME Project Team&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Yaretzi O’Sullivan&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Junior Developer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Einar Bjornsson&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Intermediate Developer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Chizoba Nwankwo&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Senior Developer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Anika Patel&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Technical Lead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ulysses St. Clair&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Intermediate Tester&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Quinton Abernathy&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Senior Tester&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Lysandra Papadopoulos&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Analyst&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ignacio Villanueva&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Engagement Lead&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h1&gt;Developers&lt;/h1&gt;
&lt;p&gt;The role of software developers is to design, develop, and maintain computer software systems. They are expected to translate software requirements into functional code, ensuring that the software meets the desired specifications and functions efficiently. Software developers typically collaborate with a team of other developers, designers, QA, analysts and engagement lead to understand user needs, brainstorm solutions, and create software solutions that address those needs. They are expected to write code using programming languages and frameworks, conduct thorough testing to identify and fix bugs or errors and optimize software performance.&lt;/p&gt;
&lt;h1&gt;Testers&lt;/h1&gt;
&lt;p&gt;The role of software testers is to ensure the quality and functionality of software applications or systems before they are released to end users. Software testers work closely with the development team to understand software requirements and design test cases and scenarios to validate the software’s performance, functionality, and usability. They execute various testing techniques, including manual and automated testing, to identify bugs, errors, and inconsistencies in the software. Software testers meticulously document and report any issues found during testing, providing clear steps to reproduce the problem and collaborating with developers to resolve them. They also perform regression testing to ensure that software updates or changes do not adversely affect previously working features. Additionally, software testers contribute to improving the overall software development process by providing feedback and suggestions to enhance software quality and user experience. They play a critical role in ensuring that the software meets quality standards and delivers a seamless user experience.&lt;/p&gt;
&lt;h1&gt;Analyst&lt;/h1&gt;
&lt;p&gt;The role of a business analyst is to bridge the gap between business objectives and technology solutions within an organization. Business analysts work closely with stakeholders from different departments to understand their needs, gather requirements, and analyze existing business processes. They conduct thorough research and data analysis to identify areas for improvement and recommend solutions that align with organizational goals. Business analysts collaborate with cross-functional teams, including the engagement lead, developers, and designers, to translate business requirements into technical specifications and ensure the successful implementation of projects. They also play a crucial role in defining project scope, creating use cases, and conducting feasibility studies to assess the viability of proposed solutions. Additionally, business analysts provide ongoing support by monitoring progress, facilitating communication between stakeholders, and conducting user acceptance testing to ensure that the delivered solution meets business requirements. Together with the engagement lead, they act as the bridge between business stakeholders and technical teams, driving effective collaboration and enabling the successful delivery of projects that meet business needs.&lt;/p&gt;
&lt;h1&gt;Technical Lead&lt;/h1&gt;
&lt;p&gt;The role of a technical lead is to provide technical guidance, mentorship, and oversight to a team of developers working on a software development project. Technical leads are expected to have in-depth knowledge of programming languages, development frameworks, and best practices. They work closely with the development team, collaborating on architectural design, code reviews, and troubleshooting technical issues. Technical leads provide guidance and direction to the team, ensuring adherence to coding standards, scalability, and maintainability of the codebase. They are responsible for ensuring priorities are completed and ensuring efficient utilization of resources within the team. Technical leads also play a crucial role in identifying and implementing technical solutions, evaluating and selecting appropriate technologies, and mitigating risks associated with the development process. They provide guidance and support to developers, while also facilitating the alignment of technical decisions with overall project goals.&lt;/p&gt;
&lt;h1&gt;Client Lead&lt;/h1&gt;
&lt;p&gt;The role of a client lead is to serve as a liaison and primary point of contact between a company or organization and its clients or stakeholders. The client lead is responsible for managing and fostering strong relationships with clients, understanding their needs and objectives, and ensuring their satisfaction with the products or services being provided. They work closely with cross-functional teams within the company to coordinate and deliver on client requirements, and they also play a crucial role in identifying opportunities for growth and expansion within existing client accounts. The client lead acts as a strategic advisor, utilizing their knowledge of the client’s business and industry to provide recommendations and solutions that drive mutual success and long-term partnerships.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Cultivating a Comprehensive Project Wiki]]></title><description><![CDATA[Photo by Wesley Tingey on Unsplash Cultivating a Comprehensive Project Wiki In software development, knowledge is both a catalyst and a…]]></description><link>http://www.drunkonmonads.com/project-wiki/</link><guid isPermaLink="false">http://www.drunkonmonads.com/project-wiki/</guid><pubDate>Wed, 25 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@wesleyphotography?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Wesley Tingey&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/stack-of-books-on-table-snNHKZ-mGfE?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Cultivating a Comprehensive Project Wiki&lt;/h1&gt;
&lt;p&gt;In software development, knowledge is both a catalyst and a safeguard. The more organized and accessible our project information is, the smoother our journey towards deployment. A Project Wiki serves as a central knowledge repository, ensuring that every team member, from developers to managers, operates with a shared understanding and easily accessible project resources. So what does a robust Project Wiki encompass? We will dive into this, serving as a guide to establishing a well-documented and insightful Project Wiki.&lt;/p&gt;
&lt;h3&gt;Resource Linkage&lt;/h3&gt;
&lt;p&gt;Document links to all pertinent project resources such as external documentation, SharePoint, project artefacts like source code and design documents, Team Communication Channels, and more. This forms the backbone of the Project Wiki, ensuring every asset is a click away.&lt;/p&gt;
&lt;h3&gt;Environment Documentation&lt;/h3&gt;
&lt;p&gt;Detail each environment (Development, Staging, Production, etc.), its purpose, links to access them, and the process to deploy or troubleshoot them (consider run-books for this). This section should demystify the environment setup&lt;/p&gt;
&lt;h3&gt;Getting Started Guide&lt;/h3&gt;
&lt;p&gt;A step-by-step guide to checking out the code, setting up the development environment, and running the project locally. Link to the README files of relevant repositories to keep the instructions up-to-date and centralized.&lt;/p&gt;
&lt;h3&gt;Repository Links&lt;/h3&gt;
&lt;p&gt;Provide links to all the repositories relevant to the project along with a brief description of the codebase each repository holds. This facilitates quick navigation and understanding of the project structure.&lt;/p&gt;
&lt;h3&gt;Team Dynamics Documentation&lt;/h3&gt;
&lt;p&gt;Outline the expectations, processes, and workflows the team adheres to. This section serves as a blueprint for how the team operates and collaborates.&lt;/p&gt;
&lt;p&gt;Specific examples&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pull Requests&lt;/strong&gt;: Detail the process for submitting, reviewing, and merging Pull Requests, underlining the importance of peer review and code quality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Coding Standards and Guidelines&lt;/strong&gt;: Document the coding conventions, best practices, and tools the team uses to maintain code quality and consistency.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Team Ceremonies&lt;/strong&gt;: Describe the routine team ceremonies like standups, sprint planning, and retrospectives, explaining their purpose and schedule.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Work Item Management&lt;/strong&gt;: Explain how work items are created, prioritized, and tracked throughout the sprint.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Team Composition and Contacts&lt;/h3&gt;
&lt;p&gt;List the team members, their roles, and contact information (particularly useful for external). Also, document the project requirements and expectations from each role, fostering clarity in responsibilities and channels of communication.&lt;/p&gt;
&lt;h3&gt;Project Requirements&lt;/h3&gt;
&lt;p&gt;Detail the project’s objectives, requirements, and any other high-level information that gives insight into what the project aims to achieve.&lt;/p&gt;
&lt;h3&gt;Run Books&lt;/h3&gt;
&lt;p&gt;Incorporate a section for run books which are essentially a compilation of procedures and operational tasks applicable to the system or software. They should cover routine operations, deployment procedures, and troubleshooting guidelines. This section ensures that there is a standard protocol to follow, reducing operational errors and enhancing efficiency.&lt;/p&gt;
&lt;h3&gt;Reason for outage tracking&lt;/h3&gt;
&lt;p&gt;Having a dedicated section for documenting outages and their root causes is crucial for future reference and for improving system reliability. Include detailed post-mortem reports, the steps taken to resolve the issues, and the measures put in place to prevent such occurrences in the future.&lt;/p&gt;
&lt;h3&gt;Releases Documentation&lt;/h3&gt;
&lt;p&gt;Maintain a thorough documentation of each release including the release date, version number, new features, bug fixes, and known issues. This section should also include rollback plans for each release to ensure system stability in case of unforeseen problems. By keeping a well-documented history of releases, team members and stakeholders can easily track the evolution of the project.&lt;/p&gt;
&lt;h3&gt;Architecture and Design&lt;/h3&gt;
&lt;p&gt;Dedicate a section to document the system’s architecture and design decisions. Include diagrams, architectural principles, and design patterns followed in the project. This section serves as a roadmap to understanding the high-level structure and the underlying rationale behind the architectural choices made within the project. Include links to more detailed design documents if available.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Creating a comprehensive Project Wiki is a proactive step towards fostering a culture of transparency, accessibility, and shared understanding within a team. It’s about laying down a foundation of knowledge that empowers every team member to operate with insight and efficiency.&lt;/p&gt;
&lt;p&gt;A key part of the success however is in keeping the content up to date and relevant as well as encouraging contributions and collaborations from the entire team. Do give sufficient attention to that.&lt;/p&gt;
&lt;p&gt;It’s also imperative to prioritize linking to existing documentation over duplicating information. Whether it’s design documents on Figma, technical specifications on SharePoint, or any other platform where project-related information resides, embedding links to these resources ensures that the Project Wiki remains a single source of truth without becoming bloated.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Enriching Code Review Culture with Pull Request Templates]]></title><description><![CDATA[Photo by Glenn Carstens-Peters on Unsplash Enriching Code Review Culture with Pull Request Templates The practice of submitting Pull…]]></description><link>http://www.drunkonmonads.com/pull-request-templates/</link><guid isPermaLink="false">http://www.drunkonmonads.com/pull-request-templates/</guid><pubDate>Wed, 25 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@glenncarstenspeters?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Glenn Carstens-Peters&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/person-writing-bucket-list-on-book-RLw-UC03Gwc?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Enriching Code Review Culture with Pull Request Templates&lt;/h1&gt;
&lt;p&gt;The practice of submitting Pull Requests (PRs) is a tradition that not only actions the introduction of changes to the code but also encourages a culture of peer review and collaborative improvement. The elegance of a PR lies in its ability to encapsulate changes, encourage discussions, and ensure a seamless merge with the existing code.&lt;/p&gt;
&lt;p&gt;This post aims to showcase not just the structural makeup of a well-curated Pull Request template to complement Pull Request processes and culture, but the underlying ethos that it carries. It’s about progressing from mere code contributors to being custodians of a culture that values clarity, collaboration, and code quality above all.&lt;/p&gt;
&lt;p&gt;However, the effectiveness of this practice relies on the quality of the information provided within a PR. An ill-described PR can easily become a hole of iterative clarifications, delayed merges, and potentially missed deadlines. Here’s where a Pull Request Template comes into play. A well-structured PR template serves to give clarity, ensuring that every proposed change is accompanied by sufficient context, visual aids, and a checklist ensuring its readiness for review. In essence, a PR template is not just a tool, but a culture-enhancer.&lt;/p&gt;
&lt;p&gt;A Pull Request (PR) Template is a predefined file that provides a structured format for developers to fill out when they create a new Pull Request on platforms such as GitHub, Azure DevOps or Bitbucket. The template is automatically populated in the pull request description field when a new pull request is created. The primary aim is to ensure consistency and quality in the information provided with each pull request, which in turn facilitates a smoother review process and better collaboration among team members.&lt;/p&gt;
&lt;p&gt;Let’s see an example of a simplistic yet effective PR template and dissect its potential impact:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;markdown&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;### Description&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;What are you changing, and what does merging this achieve?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;### Visuals&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;**Before and After**&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: If there&amp;#39;s a UI change, provide screenshots/gifs showcasing the change.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;### Checklist&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [ ] Self-review completed.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [ ] Code compiles without errors.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [ ] Relevant tests added/updated.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [ ] All tests pass locally.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [ ] Relevant documentation updated.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;💗 Thank you for contributing!&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The value given by PR template:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Explicitness&lt;/strong&gt;: By urging the contributors to provide a clear rationale and expected impact, we’re fostering a culture of accountability and clarity.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual Aids&lt;/strong&gt;: Encouraging the inclusion of visuals like screenshots can significantly accelerate the understanding of the proposed changes. This can also save the reviewer a lot of time in not having to pull down and run the changes, while still having a view and confidence of what the change looks like. PRs should emphasize code review and not be about testing changes this helps to achieve that while giving context.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Self-review Checklist&lt;/strong&gt;: A pre-merge checklist instils a sense of responsibility towards ensuring code quality and readiness.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Implementing a Pull Request template isn’t merely about adhering to a set protocol, but about nurturing a culture of better communication, self-review, and collaborative growth. It’s about making each stride towards code enhancement a well-informed, well-discussed, and well-documented journey.&lt;/p&gt;
&lt;p&gt;In fostering a culture of engineering excellence, tools and practices like a Pull Request template become indispensable allies.&lt;/p&gt;
&lt;p&gt;Go ahead and review your team’s Pull Request process. These questions can help you establish where you may find value with Pull Request templates.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What are the things you do very well that you want to continue to encourage?&lt;/li&gt;
&lt;li&gt;What are some things you can do better or that prove to be common pain points in PRs?&lt;/li&gt;
&lt;li&gt;What usually causes delays in PRs?&lt;/li&gt;
&lt;li&gt;What would make it easier or faster for reviewers to go through PRs?&lt;/li&gt;
&lt;li&gt;What is commonly forgotten by the team when making PRs?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Focus on elevating the following areas with Pull Request Templates&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consistent structure and format&lt;/li&gt;
&lt;li&gt;Information/context probing&lt;/li&gt;
&lt;li&gt;Self-check list&lt;/li&gt;
&lt;li&gt;Reducing time to approval&lt;/li&gt;
&lt;li&gt;Standardizing compliance and best practices&lt;/li&gt;
&lt;li&gt;Encouraging lean yet effective documentation that can be reviewed later&lt;/li&gt;
&lt;li&gt;Encouraging effective collaboration&lt;/li&gt;
&lt;li&gt;Increasing the quality of contributions&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Pull Request templates are meant to complement the Pull Request process and culture and can work hand in hand with other tools. For instance, a line could have been added to remind and encourage the submitter to link tickets to the Pull Request, however with something like Azure DevOps as an example, branch protection can be used to enforce that tickets should be linked to Pull Requests instead.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtkb { font-weight: bold; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk16 { color: #6796E6; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Tailoring ChatGPT Responses with Custom Instructions]]></title><description><![CDATA[Photo by Jamie Templeton on Unsplash Tailoring ChatGPT Responses with Custom Instructions Artificial Intelligence (AI) has become an…]]></description><link>http://www.drunkonmonads.com/gpt-custom-instructions/</link><guid isPermaLink="false">http://www.drunkonmonads.com/gpt-custom-instructions/</guid><pubDate>Fri, 20 Oct 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jamietempleton?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Jamie Templeton&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/brown-wooden-plank-fence-with-this-way-signboard-6gQjPGx1uQw?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Tailoring ChatGPT Responses with Custom Instructions&lt;/h1&gt;
&lt;p&gt;Artificial Intelligence (AI) has become an indispensable asset in various fields, including software engineering. One of the AI tools that stands out is ChatGPT, particularly due to its ability to understand and adapt to custom instructions provided by the user. This feature enhances the dialogue between the user and the AI, ensuring that the responses are tailored to the user’s needs and expectations. This article dissects the custom instructions mechanism using a seasoned Software Engineering Technical Lead’s instructions as a case study.&lt;/p&gt;
&lt;p&gt;ChatGPT is designed to enhance the interaction between the user and the AI by taking into consideration two key questions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;What would you like ChatGPT to know about you to provide better responses?&lt;/li&gt;
&lt;li&gt;How would you like ChatGPT to respond?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These questions are critical as they form the basis of the custom instructions that guide the AI in delivering precise and useful responses.&lt;/p&gt;
&lt;p&gt;Consider a Software Engineering Technical Lead with rich expertise in a variety of technologies and methodologies. They provided the following detailed instructions to ChatGPT:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;What would you like ChatGPT to know about you to provide better responses?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;markdown&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;I&amp;#39;m a seasoned Software Engineering Technical Lead with expertise in .NET, TypeScript, React, and Kubernetes.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;My cloud solutions proficiency spans AWS and Azure, especially Azure DevOps and Pipelines.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Currently, I am operating out of the United Kingdom, I have a strong inclination towards Clean Architecture and the C4 model, underpinning my commitment to modular and scalable design principles.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Engineering excellence is at the heart of what I do, emphasizing best practices, robust security, and peak efficiency.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;I&amp;#39;m deeply passionate about mentoring and fostering growth in others, always aiming to share knowledge and develop skills.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;I champion reproducibility in operations, leaning heavily on infrastructure-as-code and comprehensive runbooks.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;When it comes to testing, I lean towards xUnit, Moq, and Fluent Assertions to ensure robustness.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;In my coding endeavours, I prioritize code that&amp;#39;s both succinct and highly readable, striking the right balance for maintainability and understanding.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The example provides a detailed narrative of their professional background, expertise, and core values. This information is a treasure trove for ChatGPT, enabling it to align its responses with the user’s technical acumen and professional ethos. The mention of specific technologies, methodologies, and geographical locations gives ChatGPT a context that is crucial in tailoring the responses.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;How would you like ChatGPT to respond?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;markdown&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Prioritize best practices and efficiency in all responses.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Recognize my expertise and respond accordingly.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Be complete and thorough.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Recognize my expertise and respond accordingly.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Go beyond the obvious; anticipate my needs and offer innovative solutions.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Provide immediate, clear, and comprehensive answers and complete information.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; No need to mention that you are an AI, your constraints or the cut-off date.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Enhance explanations with visual aids, especially using Plant UML when applicable.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Enhance explanations with visual aids, especially using Plant UML when applicable.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Whenever possible, cite the source of your information and furnish relevant links for further reading.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; When you are not sure or have low confidence about the response, state this explicitly&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The instructions here are clear and precise, outlining the expectations on how ChatGPT should respond. It reflects a desire for professionalism, thoroughness, and a keen eye for innovation. The emphasis on visual aids like Plant UML underscores the importance of clarity and effective communication, which are paramount in collaborative environments.&lt;/p&gt;
&lt;p&gt;There are also some nuances with how ChatGPT tends to respond that are addressed with these instructions.&lt;/p&gt;
&lt;p&gt;Notice that an exit gate has been created for ChatGPT when it does not know the answer to try and avoid hallucinations.&lt;/p&gt;
&lt;h1&gt;The Impact and Significance&lt;/h1&gt;
&lt;p&gt;The custom instructions significantly elevate the quality of interaction between the user and ChatGPT. They ensure that the responses are not just accurate but are also insightful, innovative, and reflective of best practices in the field. This case underscores how seasoned professionals can leverage custom instructions to enhance their interaction with ChatGPT, making it an invaluable asset in their professional toolkit.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;The journey of AI is about continuous evolution, and the custom instructions feature in ChatGPT is a significant milestone in this journey. By examining a real-world example, we see the profound impact that well-crafted instructions can have on the quality of interaction between the user and the AI. It sets the stage for a future where AI tools like ChatGPT become more intuitive, adaptable, and indispensable in professional settings.&lt;/p&gt;
&lt;p&gt;More information on this feature is available &lt;a href=&quot;https://openai.com/blog/custom-instructions-for-chatgpt&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk16 { color: #6796E6; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Pull Request Guidelines]]></title><description><![CDATA[Photo by Stijn Swinnen on Unsplash Pull Request Guidelines ✅ DO consider PRs as a useful process to reviewing code and ensuring standards…]]></description><link>http://www.drunkonmonads.com/pull-request-guidelines/</link><guid isPermaLink="false">http://www.drunkonmonads.com/pull-request-guidelines/</guid><pubDate>Mon, 18 Sep 2023 19:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@stijnswinnen?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Stijn Swinnen&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/Q8FHN3qSq2w?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Pull Request Guidelines&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider PRs as a useful process to reviewing code and ensuring standards are followed.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create a process to ensure review of PRs is done in a timely manner to avoid blocking other team members’ progress. Not getting this right can be a common reason for a team to not commit to the process.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; provide actionable and constructive feedback when reviewing Pull Requests and be prepared to provide more time to assist in further understanding or addressing that feedback.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; encourage reviewers to be ready to pair with contributors to assist with recommendations they have provided.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; encourage reviewers to provde specific examples or suggestions when requesting changes or improvements.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; respond to comments and reply with urgency, whether you have opened the Pull Request or are a reviewer.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of various &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/project/wiki/markdown-guidance?view=azure-devops&quot;&gt;markdown features&lt;/a&gt; to make your comments easier to follow through. For example, use code fences when code is provided. Providing links is also critical.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; keep your PRs concise. Small PRs are easier to review, less error-prone, and quicker to integrate. Aim for a single concern per PR.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that the PR title is descriptive. It should give a summary of the changes, making it easier to understand the purpose of the PR at a glance.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/pull-requests?view=azure-devops&amp;#x26;tabs=browser#link-work-items-to-a-pull-request&quot;&gt;link relevant tasks, user stories, or bugs&lt;/a&gt; from Azure Boards to your PR. This provides context and allows tracking of work across the project both from the PR and from the linked work items.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Enforce this by making linked work items a requirement for a Pull Request to be merged via &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops&amp;#x26;tabs=browser#check-for-linked-work-items&quot;&gt;branch policies&lt;/a&gt;. You also get the added benefit of potentially autocompleting linked items on Pull Request merge.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/pull-requests?view=azure-devops&amp;#x26;tabs=browser#create-draft-prs&quot;&gt;draft Pull Requests&lt;/a&gt; in Azure DevOps if your changes are still in progress. This signals to reviewers that feedback is welcome, but the PR isn’t ready for final review.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; assign specific team members as reviewers based on their expertise or involvement in the code/module you’ve modified where necessary. This ensures the right eyes are on your PR.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;While this ensures the right eyes are on a PR, it should be used sparingly and necessary. It will make for better team dynamics if any team member can review Pull Requests and in the long run, this can avoid bottlenecks and potential biases.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops&amp;#x26;tabs=browser#automatically-include-code-reviewers&quot;&gt;automatically include reviewers&lt;/a&gt; on Pull Requests. You can create a group with all the team members on the team and assign this as required, meaning one team member needs to review and approve the PR before the merge&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; address review feedback promptly. This keeps the review process efficient.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/review-pull-requests?view=azure-devops&amp;#x26;tabs=browser#provide-feedback-in-comments&quot;&gt;inline or file level comments&lt;/a&gt; to provide context close to were the remarks apply on a Pull Request, either as author or reviewer.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/review-pull-requests?view=azure-devops&amp;#x26;tabs=browser#suggest-changes-in-comments&quot;&gt;suggested changes feature&lt;/a&gt; to suggest replacement text for one or more lines in a file which offers convenience for the author to apply the changes by staging a commit if they agree.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt;  make use of &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/review-pull-requests?view=azure-devops&amp;#x26;tabs=browser#change-comment-status&quot;&gt;comment statuses&lt;/a&gt; accordingly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Active&lt;/strong&gt;: the default status for new comments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pending&lt;/strong&gt;: the issue in this comment is under review and awaits something else.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Resolved&lt;/strong&gt;: the issue in this comment is addressed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Won’t fix&lt;/strong&gt;: the issue in this comment is noted but won’t be fixed.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Closed&lt;/strong&gt;: the discussion in this comment is closed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the vote feature as a reviewer to indicate your status of the review.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Approve: Approve the proposed changes in the PR. This option is just a vote and doesn’t approve the PR.&lt;/li&gt;
&lt;li&gt;Approve with suggestions: Approve the proposed changes in the PR with optional suggestions for improvement. This option is just a vote and doesn’t approve the PR.&lt;/li&gt;
&lt;li&gt;Wait for author: asks the author to review the reviewer’s comments. The PR author should let the reviewers know to re-review the code after the PR author has addressed the comments. If a required reviewer sets this vote option, the vote will block PR approval.&lt;/li&gt;
&lt;li&gt;Reject: indicates that the changes aren’t acceptable. When you choose this option, add a comment explaining why. If a required reviewer sets this vote option, the vote will block PR approval. This vote option should normally not be required.&lt;/li&gt;
&lt;li&gt;Reset feedback: clears your vote. The absence of a vote doesn’t prevent a PR from being&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/pull-requests?view=azure-devops&amp;#x26;tabs=browser#add-tags-to-a-pull-request&quot;&gt;labels and tags&lt;/a&gt; in Azure DevOps to categorize your PRs. This can help in filtering PRs based on their nature (e.g., bug, enhancement) or priority.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider pushing Pull Request notifications to the Team’s preferred messaging platform, preferably something that allows further interaction like Microsoft Teams.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; set up Azure Pipelines to conduct a &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops&amp;#x26;tabs=browser#build-validation&quot;&gt;pre-merge build&lt;/a&gt; to ensure the changes don’t break the main branch. This is essential to maintain the health of your main branch. Create at minimum a CI pipeline for your PRS to ensure that code compiles, tests and linting succeeds among other things.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Do similar checks on merging a branch as verifying a branch does not guarantee that the code will necessarily be sane once merged. Consider checks like builds, test runs, deployments to a development environment etc. Your Pull Request checks may include things you may want to omit in these checks like linting.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; configure your PR settings to require &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops&amp;#x26;tabs=browser#require-a-minimum-number-of-reviewers&quot;&gt;at least one (or more) approval&lt;/a&gt; before merging. This ensures that every change has been vetted by another set of eyes.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; configure your PR settings to &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops&amp;#x26;tabs=browser#limit-merge-types&quot;&gt;allow only the merge types&lt;/a&gt; that match your team branching strategies. Azure Repos has several merge strategies, and by default, all of them are allowed. You can maintain a consistent branch history by enforcing a merge strategy for PR completion.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; configure your PR settings to &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops&amp;#x26;tabs=browser#check-for-comment-resolution&quot;&gt;require comment resolution&lt;/a&gt; before merging.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider an exit hatch to &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/branch-policies?view=azure-devops&amp;#x26;tabs=browser#bypass-branch-policies&quot;&gt;bypass branch policies&lt;/a&gt; by granting bypass permission to a user or group. In some cases, you might need to bypass policy requirements so having this exit hatch would be handy, however, you must ensure that this is not abused.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/complete-pull-requests?view=azure-devops&amp;#x26;tabs=browser#complete-automatically&quot;&gt;enabling autocomplete&lt;/a&gt; on creating a Pull Request. This automatically completes a Pull Request once it fulfils all policies and also allows for automatically completing associated work items and deleting the branch after merging.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;It is highly encouraged to always enable this with the branch deletion ticked to keep the remote clean.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; encourage &lt;code class=&quot;language-text&quot;&gt;drive by&lt;/code&gt; reviews. Even if one person has taken ownership or reviewed a Pull Request, it should be fine and is quite beneficial for someone else with the capacity to join and ask questions or make additional comments.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; encourage the creation of new work items based on suggestions that are great but outside the scope of the current Pull Request. This avoids slowing down the review process while still considering great suggestions that go through the triage and prioritization processes of the team.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; encourage an environment where it is OK to disagree with Pull Request review remarks or how an implementation has been done, however politely and constructively. Encourage discussions and feedback in PRs, and always be respectful and adhere to your team’s standards and practices&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Effort in ensuring the team has a shared view on coding practices and principles, architecture etc. makes it easier to be constructive in feedback as there is always a reference point on the agreed upon team approach, which however should not be the law but can also be challenged as the team learns more from the project and grows&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; look out for common and recurring feedback and find ways to automate the checks. A lot of linting-esque tools can be used to automate such checks, for example Roslyn Analyzers and the &lt;a href=&quot;https://learn.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2022&quot;&gt;Editor Config&lt;/a&gt; in .NET with dotnet tools like &lt;a href=&quot;https://github.com/dotnet/format&quot;&gt;dotnet-format&lt;/a&gt;, &lt;a href=&quot;https://eslint.org/&quot;&gt;ES Lint&lt;/a&gt; for JavaScript/TypeScript, &lt;a href=&quot;https://hadolint.github.io/hadolint/&quot;&gt;Hadolint&lt;/a&gt; for Docker files, &lt;a href=&quot;https://github.com/yannh/kubeconform&quot;&gt;kubeconform&lt;/a&gt; for Kubernetes, [Spectral] for OpenAPI and more.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use CI tools to automate linting, coding practices, test runs, and other checks to streamline code reviews and maintain code quality. Do this with PR comments that become regular.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;See Github’s &lt;a href=&quot;https://github.com/super-linter/super-linter&quot;&gt;Super-Linter&lt;/a&gt; for inspiration on some linters that can be used in Github actions and independently elsewhere, for example from Azure Pipelines.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use a &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/devops/repos/git/pull-request-templates?view=azure-devops&quot;&gt;Pull Request template&lt;/a&gt; to standardize the information provided when opening a PR. This ensures consistency and provides reviewers with the necessary context.&lt;/p&gt;
&lt;p&gt;Example&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;### Description&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;What are you changing, and what does merging this achieve? Why is this change being made?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;### Screenshots&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Is this a UX change or can screenshots help the reviewer see the before and after or understand the solution better? Do you have any manual testing evidence?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;### Checklist&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;- [ ] Self-review complete&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;- [ ] Code builds without errors&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;- [ ] Relevant tests have been authored/updated&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;- [ ] All tests are passing locally&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;- [ ] Relevant documentation updates have been made&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;💗 Thank you for your contribution!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[How to modify data in a temporal/versioned table]]></title><description><![CDATA[Photo by Jan Antonin Kolar on Unsplash How to modify data in a temporal/versioned table Temporal tables, also known as system-versioned…]]></description><link>http://www.drunkonmonads.com/modify-data-in-temporal-tables/</link><guid isPermaLink="false">http://www.drunkonmonads.com/modify-data-in-temporal-tables/</guid><pubDate>Tue, 29 Aug 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jankolar?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Jan Antonin Kolar&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/lRoX0shwjUQ?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;How to modify data in a temporal/versioned table&lt;/h1&gt;
&lt;p&gt;Temporal tables, also known as system-versioned temporal tables, allow you to keep a full history of data changes in a separate table called a history table. This history table is linked to the main table and is automatically populated by the database system whenever a row in the main table is updated or deleted.&lt;/p&gt;
&lt;p&gt;Given this behavior, direct modifications (like DELETE or UPDATE operations) to the history table are generally not allowed, to ensure data integrity and the accuracy of the history.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ If you’re trying to delete rows from the main table, and an error is being raised, make sure you’re not directly targeting the history table by mistake. If you delete rows from the main table, the corresponding rows in the history table will be preserved (that’s the whole point of temporal tables). If you’re trying to clean up or archive old history data, consider looking into best practices for managing data in temporal tables.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If you really need to modify the history table:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;sql&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;-- Set system-versioning to OFF&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;ALTER&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;TABLE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; YourMainTableName &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SET&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SYSTEM_VERSIONING&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;OFF&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;-- Make your changes to the history table&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;-- Set system-versioning back to ON&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;ALTER&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;TABLE&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; YourMainTableName &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SET&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SYSTEM_VERSIONING&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ON&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (HISTORY_TABLE = YourHistoryTableName));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[API Design Guidelines for Success]]></title><description><![CDATA[Photo by Douglas Lopes on Unsplash API Design Guidelines for Success Introduction In today’s fast-paced world of software development, the…]]></description><link>http://www.drunkonmonads.com/api-design-guidelines/</link><guid isPermaLink="false">http://www.drunkonmonads.com/api-design-guidelines/</guid><pubDate>Fri, 21 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@douglasamarelo?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Douglas Lopes&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/ehyV_XOZ4iA?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;API Design Guidelines for Success&lt;/h1&gt;
&lt;p&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In today’s fast-paced world of software development, the quality of your APIs can make or break your project. Well-designed APIs are not only user-friendly but also set the stage for robust and scalable applications. In this comprehensive guide, we’ll explore API Design Guidelines that will pave the way for your API’s success.&lt;/p&gt;
&lt;h2&gt;Why API Design Matters&lt;/h2&gt;
&lt;p&gt;APIs (Application Programming Interfaces) serve as the bridge between different software components, allowing them to communicate and exchange data. A well-designed API can:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Improve developer experience by prioritizing simplicity and comprehensibility.&lt;/li&gt;
&lt;li&gt;Enhance long-term maintainability and consistency.&lt;/li&gt;
&lt;li&gt;Promote scalability and adaptability to evolving business requirements.&lt;/li&gt;
&lt;li&gt;Ensure secure and efficient data exchange.&lt;/li&gt;
&lt;li&gt;Facilitate collaboration among development teams.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, let’s dive into the API design principles that can help you achieve these goals.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; prioritize simplicity, comprehensibility, and usability to create an irresistible appeal for consuming engineers.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; actively improve and maintain API consistency over the long term.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; generalized business requirements to avoid use-case-specific APIs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Do design with this evolution in mind and specifically to avoid breaking changes to the consumers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt;  use a standard format for date and time values.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Use the string-typed formats &lt;code class=&quot;language-text&quot;&gt;date&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;date-time&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;time&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;duration&lt;/code&gt;, or &lt;code class=&quot;language-text&quot;&gt;period&lt;/code&gt; for the definition of date and time properties. The formats are based on the standard &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc3339&quot;&gt;RFC 3339&lt;/a&gt; internet profile — a subset of &lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc3339#ref-ISO8601&quot;&gt;ISO 8601&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use standard formats for country, language and currency properties.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2&quot;&gt;ISO 3166-1-alpha-2&lt;/a&gt; for country codes&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes&quot;&gt;ISO 639-1&lt;/a&gt; for language codes&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/ISO_4217&quot;&gt;ISO 4217&lt;/a&gt; for currency codes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;UUIDs&lt;/code&gt; for IDs to avoid scaling problems in high-frequency use cases.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consistently use plurals for resource names.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; think of resources and avoid actions.&lt;/p&gt;
&lt;p&gt;Good&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;http&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;PUT /users/{user-id}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bad&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;http&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;PUT /getUser&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; apply domain-specific resource names.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; Identify resources and sub-resources with path segments.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;http&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;/resources/{resource-id}/sub-resources/{sub-resource-id}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use nouns and &lt;strong&gt;NOT verbs&lt;/strong&gt; for resource names.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# bad&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;/getCompanies&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# good&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;/companies&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Other examples&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;GET /users&lt;/code&gt; to retrieve a list of users&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;GET /users/{id}&lt;/code&gt; to retrieve a specific user by ID&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;POST /users&lt;/code&gt; to create a new user&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;PUT /users/{id}&lt;/code&gt; to update a specific user&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;DELETE /users/{id}&lt;/code&gt; to delete a specific user&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create types that convey the complete meaning for example favor types like stringified timestamps to convey relative time or types that carry the unit to explicitly communicate this.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;weight&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;68.0388555&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;unit&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;kg&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;# consider this as an alternative to the duration format&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;timeDuration&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;01:30:00&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; pluralize array names.&lt;/p&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;null&lt;/code&gt; for empty arrays.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; explicitly name dates with &lt;code class=&quot;language-text&quot;&gt;date&lt;/code&gt; as a suffix or consider suffixes like &lt;code class=&quot;language-text&quot;&gt;at&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use casing consistently across the API for operation ID, query parameters, path parameters, and property names in payloads.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;camelCase&lt;/code&gt; for operation IDs, paths and schemas properties&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;snake_case&lt;/code&gt; for parameters&lt;/li&gt;
&lt;li&gt;Choose a casing and stick to it for body content and stick to it, the preferable &lt;code class=&quot;language-text&quot;&gt;JSON&lt;/code&gt; with camelCase&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the appropriate &lt;code class=&quot;language-text&quot;&gt;HTTP&lt;/code&gt; method for each operation. Standard methods include &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; (retrieve), &lt;code class=&quot;language-text&quot;&gt;POST&lt;/code&gt; (create), &lt;code class=&quot;language-text&quot;&gt;PUT&lt;/code&gt; (update), &lt;code class=&quot;language-text&quot;&gt;PATCH&lt;/code&gt; (partial update), and &lt;code class=&quot;language-text&quot;&gt;DELETE&lt;/code&gt; (delete).&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; avoid &lt;code class=&quot;language-text&quot;&gt;PUT&lt;/code&gt; requests that do not end with path parameters. For example, use &lt;code class=&quot;language-text&quot;&gt;/api/products/{product_id}&lt;/code&gt; instead of a more generic endpoint like &lt;code class=&quot;language-text&quot;&gt;/api/products/update&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; not return response bodies as a bare array, always nest in an object. As your API evolves and new fields or metadata need to be included in the response, it is easier to extend an object rather than a bare array. Additionally, when responses are nested in an object, it becomes straightforward to include relevant error information alongside the data.&lt;/p&gt;
&lt;p&gt;Good&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;data&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Product A&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Product B&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bad&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Product A&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;id&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Product B&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; apply care with required types that may surface with default in &lt;code class=&quot;language-text&quot;&gt;JSON&lt;/code&gt; or the language of the server implementation for these like numerics and enumerations. For validation and sanity purposes, it is great to make a distinction between not provided (null) vs a default especially when the values carry semantic meaning in the domain which can cause tough-to-track data corruption issues.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; return bodies for all &lt;code class=&quot;language-text&quot;&gt;2xx&lt;/code&gt; responses except &lt;code class=&quot;language-text&quot;&gt;204&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; avoid &lt;code class=&quot;language-text&quot;&gt;POST&lt;/code&gt; for operations that create resources.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that an operation that returns a list that is potentially large supports pagination.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;http&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;GET /api/products?offset=1&amp;amp;limit=20&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that an operation that returns 202 should not return other 2XX responses.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that all parameters for an operation are case-insensitive and unique.&lt;/p&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; create &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; long-running operations. The reason for this is that &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; requests are meant to be used for retrieving data from the server, and they are expected to be relatively fast and non-blocking.&lt;/p&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; return a body with a &lt;code class=&quot;language-text&quot;&gt;204&lt;/code&gt; response. The HTTP status code &lt;code class=&quot;language-text&quot;&gt;204 No Content&lt;/code&gt; should not have a response body according to the &lt;code class=&quot;language-text&quot;&gt;HTTP/1.1&lt;/code&gt; specification. When a server returns a &lt;code class=&quot;language-text&quot;&gt;204 No Content&lt;/code&gt; status code, it indicates that the request was successful, but there is no additional content to send in the response payload.&lt;/p&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; accept a body for a &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;DELETE&lt;/code&gt; request. According to &lt;code class=&quot;language-text&quot;&gt;HTTP/1.1&lt;/code&gt; specifications, &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;DELETE&lt;/code&gt; requests should not have a request body. Both &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;DELETE&lt;/code&gt; methods are considered “safe” methods, meaning they should not have any significant side effects on the server’s resources or data. As a result, including a request body for &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;DELETE&lt;/code&gt; requests goes against the intended semantics of these &lt;code class=&quot;language-text&quot;&gt;HTTP&lt;/code&gt; methods.&lt;/p&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; use special characters in paths. The use of special characters in paths can lead to issues with parsing, encoding, and security, and it may confuse both API consumers and developers.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;http&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# Bad&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;/api/user-profiles/{user-id}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;GET&lt;/code&gt; for operations that change state. It should be safe and idempotent, meaning it can be called any number of times without changing the result.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the appropriate HTTP status codes to indicate the outcome of the operation. &lt;code class=&quot;language-text&quot;&gt;2xx&lt;/code&gt; for success, &lt;code class=&quot;language-text&quot;&gt;4xx&lt;/code&gt; for client errors, and &lt;code class=&quot;language-text&quot;&gt;5xx&lt;/code&gt; for server errors. The following are common response types that you will likely need to use:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;200 OK&lt;/code&gt;: The request has succeeded.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;201 Created&lt;/code&gt;: The request has been fulfilled, and a new resource has been created.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;202 Accepted&lt;/code&gt;: The request has been accepted for processing, but the processing is not yet complete.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;204 No Content&lt;/code&gt;: The server has successfully processed the request, but there is no content to send back.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;207 Multi-Status&lt;/code&gt;: The response body contains status information for multiple different parts of a batch/bulk request&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;400 Bad Request&lt;/code&gt;: The server cannot understand the request due to invalid syntax or other client-side errors.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;401 Unauthorized&lt;/code&gt;: The request requires user authentication or the authentication has failed.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;403 Forbidden&lt;/code&gt;: The server understood the request but refused to authorize it.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;404 Not Found&lt;/code&gt;: The requested resource could not be found on the server.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;405 Not Found&lt;/code&gt;: The method is not supported, and handled out of the box by most server frameworks.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;409 Conflict&lt;/code&gt;: The request cannot be completed due to conflict with the current state of the target resource.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;500 Internal Server Error&lt;/code&gt;: An unexpected error occurred on the server.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;503 Service Unavailable&lt;/code&gt;: The server is currently unable to handle the request due to temporary overload or maintenance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; return meaningful error messages with appropriate HTTP status codes.&lt;/p&gt;
&lt;p&gt;Example Bad Request response&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;10&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;errors&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Deal&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;#39;User ID&amp;#39; must not be empty.&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;https://tools.ietf.org/html/rfc7231#section-6.5.1&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;title&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;One or more validation errors occurred.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;status&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;400&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;traceId&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;00-2a45f765492f8b44e8b42296ce8b37f8-2ad0369bf4ca922a-00&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Matching schema&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;11&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;schemas&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;object&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;uri-reference&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The error type.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The error title.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;integer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;format&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;int32&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The `HTTP` error status code.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;400&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;traceId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The internal error trace ID&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;badRequestResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;allOf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/schemas/error&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;object&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Bad Request response.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;errors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;allOf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/schemas/badRequestResponseError&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;A specific error from the request input.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;object&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;badRequestResponseError&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;object&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;A Bad Request error response.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;additionalProperties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;array&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Properties with validation errors.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;User ID must not be empty&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;responses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;BadRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Bad Request (validation failure - DO NOT RETRY).&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/schemas/badRequestResponse&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; version your API to allow changes without breaking existing clients. This can be done via the URL (&lt;code class=&quot;language-text&quot;&gt;/v1/users&lt;/code&gt;) or headers (&lt;code class=&quot;language-text&quot;&gt;Accept-version: v1&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;Without versioning, making changes to your API can break existing clients.&lt;/p&gt;
&lt;p&gt;⚠️ Parameter versioning is not recommended because versioning is not an optional feature or filter, and should not be treated as such&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;http&quot; data-index=&quot;12&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;GET /users?version=1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; limit array, string and integer sizes to mitigate resource exhaustion attacks.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use HTTPS for secure connections, except when a local host is used.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that path parameters use random IDs that cannot be guessed, such as UUIDs. Using UUIDs as path parameters is a straightforward way to enhance the security and privacy of your API, prevent unauthorized access, and ensure global uniqueness.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;http&quot; data-index=&quot;13&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# Good&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;GET /api/users/82556e7a-0d8a-4c87-98e7-7395f0f8a3e6&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use token-based authentication: Tokens like JWT can be used to authenticate users. Tokens should be included in the Authorization header of the HTTP request.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Security scheme description must state that the implementation conforms with JSON Web Tokens RFC7519, the JSON Web Token standard.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;http&quot; data-index=&quot;14&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;GET /users&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Authorization: Bearer &amp;lt;token&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; expose sensitive information in error messages, such as database details or confidential data.&lt;/p&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; expose credentials like API keys, passwords, secrets or personally identifiable information (PII) in query parameters.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;http&quot; data-index=&quot;15&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# Bad&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;GET /api/data?api_key=your_api_key_here&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; use the &lt;code class=&quot;language-text&quot;&gt;Basic Auth&lt;/code&gt; security schema. Use a more secure authentication method like &lt;code class=&quot;language-text&quot;&gt;OAuth 2.0&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;16&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# BAD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;http://api.yourwebsite.com/users?password=secretPassword&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;🎇 &lt;strong&gt;DO&lt;/strong&gt; implement rate limiting to protect the API against abuse and denial-of-service attacks.&lt;/p&gt;
&lt;p&gt;When a client exceeds the rate limit, you should return a 429 Too Many Requests HTTP status code, along with a message indicating that the rate limit has been exceeded.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;http&quot; data-index=&quot;17&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;HTTP/1.1 429 Too Many Requests&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Content-Type: text/html&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Retry-After: 3600&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    &amp;quot;message&amp;quot;: &amp;quot;Rate limit exceeded. Try again in 3600 seconds.&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;Retry-After&lt;/code&gt; header indicates how many seconds the client should wait before making another request.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; provide comprehensive API documentation, including available endpoints, request/response examples, error messages, etc. Tools like Swagger or Redoc can be used for interactive documentation.&lt;/p&gt;
&lt;p&gt;Documentation should include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The HTTP methods and endpoints available.&lt;/li&gt;
&lt;li&gt;The request format including headers and body (with examples).&lt;/li&gt;
&lt;li&gt;The response format includes status codes, headers, and body (with examples).&lt;/li&gt;
&lt;li&gt;Any error messages that the API could return.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;http&quot; data-index=&quot;18&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Endpoint: GET /users/{id}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Description: Fetches a user with the given ID.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Headers:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Authorization: Bearer {token}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Path parameters:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;id - The ID of the user to fetch.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Example request:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;GET /users/123&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;Example response:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;200 OK&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    &amp;quot;id&amp;quot;: 123,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    &amp;quot;name&amp;quot;: &amp;quot;John Doe&amp;quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    &amp;quot;email&amp;quot;: &amp;quot;john.doe@example.com&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; provide a consistent response format. Most RESTful APIs use JSON.&lt;/p&gt;
&lt;p&gt;Using a consistent, well-structured response format makes your API easier to use and understand. It can also make it easier for clients to predict how your API will behave and to handle responses programmatically.&lt;/p&gt;
&lt;h3&gt;Linting and enforcing standards&lt;/h3&gt;
&lt;p&gt;For linting APIs, tools like Spectral can be used. It checks an OpenAPI document for issues like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Compliance with naming conventions.&lt;/li&gt;
&lt;li&gt;Missing required fields.&lt;/li&gt;
&lt;li&gt;Incorrect data types.&lt;/li&gt;
&lt;li&gt;Ensuring examples match the schema.&lt;/li&gt;
&lt;li&gt;Ensuring paths are unique.&lt;/li&gt;
&lt;li&gt;Enforcing best practices for versioning, parameters, responses, etc.&lt;/li&gt;
&lt;li&gt;Custom rules defined as per the organization’s/team’s standards.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Open API Spec&lt;/h1&gt;
&lt;p&gt;The &lt;a href=&quot;https://swagger.io/specification/&quot;&gt;Open API Specification&lt;/a&gt; (formerly known as Swagger Specification) is an industry-standard specification for defining, documenting, and describing RESTful APIs. It is a language-agnostic and machine-readable format used to describe the structure and behaviour of APIs, making it easier for developers and computers to understand and interact with the API.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A good way to understand the specification is to navigate the &lt;a href=&quot;https://openapi-map.apihandyman.io/&quot;&gt;Open API mind map&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The specification is typically written in JSON or YAML format and defines various aspects of the API, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;API Endpoints: It defines the available API endpoints (URLs) along with their supported HTTP methods (GET, POST, PUT, DELETE, etc.).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Request and Response Parameters: It specifies the parameters that can be sent in API requests and the data expected in API responses.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Data Models: These describe the data models and structures used in API requests and responses.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Authentication and Security: It defines how clients can authenticate themselves to access the API securely.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Error Handling: It describes how errors and error responses are handled by the API.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;API Versioning: It provides a mechanism for versioning the API to support backward compatibility.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;API Documentation: The Open API Specification can also include human-readable documentation to explain how to use the API effectively.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; call for early peer/ client consumer review of the API and set clear expectations for the review process.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider &lt;code class=&quot;language-text&quot;&gt;YAML&lt;/code&gt; when creating Open API specification for the following reasons:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Human-Readable Format&lt;/strong&gt;: YAML has a more human-friendly and easy-to-read syntax compared to JSON. It uses indentation and whitespace, making it visually clearer and more natural to work with, especially when dealing with complex data structures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Concise Syntax&lt;/strong&gt;: YAML allows the omission of unnecessary punctuation and closing tags, leading to a more concise representation of data. This can result in shorter and more readable OpenAPI specifications.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Easier Comments&lt;/strong&gt;: YAML supports inline comments, making it simpler to include explanatory notes within the specification. Comments help improve the clarity and understanding of the API design for developers and other stakeholders.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Multiple Documents in One File&lt;/strong&gt;: YAML allows multiple documents to be defined in a single file, separated by three hyphens (---). This feature can be useful when managing related but distinct API specifications, allowing them to be kept together for convenience.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Built-in Support for Lists and Maps&lt;/strong&gt;: YAML has native support for lists (arrays) and maps (objects), making it more intuitive to define complex data structures. This is especially useful when specifying request and response parameters for API endpoints.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Some tools allow for conversion between &lt;code class=&quot;language-text&quot;&gt;JSON&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;YAML&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider Open API spec first approaches when in the design phase. This can open up many advantages&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Clarity and Collaboration&lt;/strong&gt;: Starting with an Open API specification allows you to define the API contract clearly and comprehensively. This specification acts as a single source of truth that fosters collaboration among various stakeholders, such as developers, designers, and testers. Everyone works based on the same specifications, reducing misunderstandings and miscommunications.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API Design Early in the Process&lt;/strong&gt;: By focusing on the API specification at the beginning of the development process, you can design the API’s structure, endpoints, parameters, and responses thoroughly before implementing any actual code. This helps in making informed decisions and reduces the risk of rework or changes later in the development process.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Client-Server Independence&lt;/strong&gt;: The OpenAPI specification allows developers to design APIs independently of the client or server implementation. This promotes the separation of concerns and allows teams to work concurrently on the API and the client or server implementations, making development more efficient.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Automated Documentation&lt;/strong&gt;: The OpenAPI specification can be leveraged to generate interactive and comprehensive API documentation automatically.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code Generation&lt;/strong&gt;: There are many tools out there that support the generation of server and client code for various platforms and languages which can greatly accelerate development.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that the following information is always present in your specification&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Tags, with descriptions&lt;/li&gt;
&lt;li&gt;API host&lt;/li&gt;
&lt;li&gt;API schemas&lt;/li&gt;
&lt;li&gt;Info contact&lt;/li&gt;
&lt;li&gt;Operation IDs&lt;/li&gt;
&lt;li&gt;Security definition&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that all operations are unique.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; version your API specifications and consider the &lt;code class=&quot;language-text&quot;&gt;YYYY-MM-DD&lt;/code&gt; format, optionally suffixed with ‘-preview’ over semantic versioning with numbers.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; always specify the &lt;code class=&quot;language-text&quot;&gt;format&lt;/code&gt; of integer values as either &lt;code class=&quot;language-text&quot;&gt;int32&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;int64&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that all operations have at least one tag.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that every operation has at least one &lt;code class=&quot;language-text&quot;&gt;2xx&lt;/code&gt; response.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that all schema properties have a defined type.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that all path parameters are of type string and specify the &lt;code class=&quot;language-text&quot;&gt;maxLength&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;pattern&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; provide descriptions for all schema properties.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; be careful of the source of the documentation for security reasons.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Apply linting to ensure that you do not have &lt;code class=&quot;language-text&quot;&gt;eval&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;script&lt;/code&gt; tags in the markdown.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; create paths that end in a trailing slash (&lt;code class=&quot;language-text&quot;&gt;/&lt;/code&gt;).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Tooling is inconsistent in how this is handled and this could lead to issues.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; explicitly define the &lt;code class=&quot;language-text&quot;&gt;Authorization&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Content-type&lt;/code&gt;, and Accept headers.&lt;/p&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; provide defaults for required parameters or properties.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You need to be able to make the distinction between a required property that is empty vs a default being provided.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; inline types, instead always explicitly define a schema.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Doing this consistently is great and also makes it easy to see all the schema definitions in one place and avoid duplications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Sample showing some of what is highlighted in this document&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;yaml&quot; data-index=&quot;19&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;contact name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;email&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;contact email&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;x-audience&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;audience&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;servers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;base url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;v1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;tag name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;components&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;schemas&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;provinces&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;An enumeration of all the supported provinces.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Gauteng&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;WesternCape&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;EasternCape&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;KwaZuluNatal&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;FreeState&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Limpopo&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Mpumalanga&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;NorthernCape&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;NorthWest&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;object&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;An address.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;line1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The first line of the address&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Apartment 4B&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;line2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The second line of the address&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;123 Main Street&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;suburb&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The address suburb&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Willow Creek&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;city&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;string&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The address city&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Johannesburg&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;province&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;allOf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/schemas/provinces&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The address province&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;example&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Gauteng&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;postalCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;allOf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/schemas/postalCode&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;The address postal code&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;line1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;suburb&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;city&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;province&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;postalCode&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;responses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;BadRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/schemas/badRequestResponse&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;paths&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;/user/address&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;post&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;operationId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;updateUserAddress&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        - [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;requestBody&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/schemas/address&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;responses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;202&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;application/json&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;schema&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/schemas/addressUpdatedResponse&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;400&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/responses/BadRequest&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;401&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/responses/UnauthorizedError&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;404&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/responses/NotFound&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;415&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/responses/UnsupportedMediaType&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;500&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;$ref&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#/components/responses/InternalServerError&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;API consumer manual&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider creating a user manual to complete the API to be shared with all stakeholders.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This does not have to be the classic manual as a document like a &lt;code class=&quot;language-text&quot;&gt;PDF&lt;/code&gt;, but would be much better as a living resource like a Postman collection that can be complete with extensive documentation and use case-specific examples that can easily be run on demand.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Spectral&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://meta.stoplight.io/docs/spectral/674b27b261c3c-overview&quot;&gt;Spectral&lt;/a&gt; is an open-source tool designed to enforce API design best practices and ensure API specifications (such as Open API or Swagger) adhere to specific rules and guidelines. It acts as a linter, which means it checks API definitions against a set of pre-defined rules or custom rules to identify potential issues or deviations from best practices.&lt;/p&gt;
&lt;p&gt;The primary purpose of Spectral is to improve the quality and consistency of API specifications by providing automated checks on various aspects of the API design. This includes checking for naming conventions, validation of data types and formats, ensuring required fields are present, and detecting other common mistakes or discrepancies.&lt;/p&gt;
&lt;p&gt;See &lt;a href=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/res/.spectral.yml&quot;&gt;here&lt;/a&gt; a recommended configuration that encompasses all the design guidelines discussed in this document.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Creating well-designed APIs is essential for building successful software applications. By adhering to these API design guidelines, you’ll improve developer experience, ensure long-term maintainability, and promote scalability and security. Remember, a well-designed API is not only a technical asset but also a strategic one.&lt;/p&gt;
&lt;p&gt;Ready to implement these guidelines? Start by reviewing your existing APIs and making improvements where necessary. Your users and fellow developers will thank you for it!&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[TypeScript and Angular Standards]]></title><description><![CDATA[Photo by Tim Wildsmith on Unsplash Node ✅ DO  over  when running installs in continuous integration. Utilizing this in continuous…]]></description><link>http://www.drunkonmonads.com/typescript-angular-standards/</link><guid isPermaLink="false">http://www.drunkonmonads.com/typescript-angular-standards/</guid><pubDate>Wed, 19 Jul 2023 19:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@timwildsmith?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Tim Wildsmith&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/UsR0MDtB7Sc?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Node&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; &lt;code class=&quot;language-text&quot;&gt;npm ci&lt;/code&gt; over &lt;code class=&quot;language-text&quot;&gt;npm i&lt;/code&gt; when running installs in continuous integration. Utilizing this in continuous integration workflows, such as Azure DevOps, offers significant benefits for reliable and reproducible builds. Unlike &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt;, which can have varying outcomes due to the &lt;code class=&quot;language-text&quot;&gt;package-lock.json&lt;/code&gt; file, npm ci ensures deterministic package installations and fosters consistent build results&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Deterministic Installations&lt;/strong&gt;: With &lt;code class=&quot;language-text&quot;&gt;npm ci&lt;/code&gt;, you can be confident that the exact versions of packages listed in the &lt;code class=&quot;language-text&quot;&gt;package-lock.json&lt;/code&gt; file will be installed. It disregards any existing &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; folder and starts from scratch, guaranteeing a reproducible environment across CI builds. This eliminates potential issues caused by conflicting or mismatched dependencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster and Reliable Builds&lt;/strong&gt;: By leveraging the &lt;code class=&quot;language-text&quot;&gt;package-lock.json&lt;/code&gt; file, &lt;code class=&quot;language-text&quot;&gt;npm ci&lt;/code&gt; performs faster installations compared to &lt;code class=&quot;language-text&quot;&gt;npm install&lt;/code&gt;. It bypasses dependency resolution, fetching packages directly based on the &lt;code class=&quot;language-text&quot;&gt;lockfile&lt;/code&gt;. Consequently, it reduces network requests, resulting in faster and more reliable builds, which is particularly valuable in time-sensitive CI processes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CI-Friendly Caching&lt;/strong&gt;: In CI environments, caching is vital to optimize build times. With &lt;code class=&quot;language-text&quot;&gt;npm ci&lt;/code&gt;, the &lt;code class=&quot;language-text&quot;&gt;lockfile&lt;/code&gt; integrity check is more straightforward, making it easier to leverage caching mechanisms. By caching the &lt;code class=&quot;language-text&quot;&gt;node_modules&lt;/code&gt; directory and the &lt;code class=&quot;language-text&quot;&gt;package-lock.json&lt;/code&gt; file, subsequent CI builds can benefit from faster dependency restoration, providing efficient pipeline execution&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;TypeScript and Angular Standards&lt;/h1&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use string interpolation when creating &lt;code class=&quot;language-text&quot;&gt;HTTP&lt;/code&gt; requests for the request parameters and instead make use of &lt;code class=&quot;language-text&quot;&gt;HttpParams&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BAD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;preVetCreditApplication&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;creditApplicationId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dealId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Observable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;PrevettingResponseDto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  const &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;baseUrl&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;/v1/CreditApplications/prevet?creditApplicationId=&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;creditApplicationId&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;amp;dealId=&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dealId&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  return this.http.get&amp;lt;PrevettingResponseDto&amp;gt;(url);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// GOOD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;preVetCreditApplication&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;creditApplicationId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dealId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;): &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Observable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;PrevettingResponseDto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  const &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpParams&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    .set(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;creditApplicationId&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, creditApplicationId)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    .set(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dealId&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, dealId);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  return this.http.get&amp;lt;PrevettingResponseDto&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;baseUrl&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;/v1/CreditApplications/prevet`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;params&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using &lt;code class=&quot;language-text&quot;&gt;HttpParams&lt;/code&gt; the code becomes more readable and self explanatory especially when there are a lot of parameters involved. More importantly this allows for dynamic handling of parameters with conditionals and parameter serialization ensuring that the values are properly encoded for URL transmission. This eliminates the need to manually handle encoding concerns, reducing the risk of errors and security vulnerabilities.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; make use of &lt;code class=&quot;language-text&quot;&gt;as&lt;/code&gt; unless absolutely required. Type assertions with as in TypeScript remove static type checking which can lead to issues.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BAD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// adding a new property on User for instance would not cause an error here&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;John Doe&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// GOOD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;John Doe&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor the use of immutable variables where possible. Immutable variables are easier to reason about as no change is anticipated.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fileToLoad&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;documents&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;connected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fileToLoad&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;documents-other&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// can be collapsed into&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fileToLoad&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;connected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ? &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;documents&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;documents-other&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// easier to read, easier to reason about&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor the use of absolute imports over relative imports.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// given src/services/translate.ts&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// an import from /src/../something.ts&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;../../services/translate&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// changes to regardless of where imported from&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;services/translate&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Can be achieved by adding the following to tsconfig.json&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;compilerOptions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;baseUrl&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;src&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we want to tell local imports apart from rest we can use aliasing&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;compilerOptions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;baseUrl&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;./&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;paths&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;~component/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;src/components/_&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;     }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// import {Login} from ‘~component/Login;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; prefer use of interfaces. Use type when you need specific features offered by types.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;const&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;let&lt;/code&gt; over &lt;code class=&quot;language-text&quot;&gt;var&lt;/code&gt;, using let only where mutation is expected. The scoping semantics of var lead to bugs.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;!x&lt;/code&gt; instead of &lt;code class=&quot;language-text&quot;&gt;x==null&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;//&amp;#39;x&amp;#39; is falsey, so it will evaluate to false when undefined, null or zero (0)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor the use of the use of modern javascript features over the more classic counterparts. Examples of features to be familiar with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Template literals (string interpolation)&lt;/li&gt;
&lt;li&gt;Rest and spread operators&lt;/li&gt;
&lt;li&gt;Destructuring assignments&lt;/li&gt;
&lt;li&gt;Object literals&lt;/li&gt;
&lt;li&gt;Arrow functions&lt;/li&gt;
&lt;li&gt;Yield&lt;/li&gt;
&lt;li&gt;Ternary operator&lt;/li&gt;
&lt;li&gt;Nullish coalescing operator&lt;/li&gt;
&lt;li&gt;Promises&lt;/li&gt;
&lt;li&gt;async and await&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; familiarize yourself with array methods.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;find&lt;/li&gt;
&lt;li&gt;some&lt;/li&gt;
&lt;li&gt;every&lt;/li&gt;
&lt;li&gt;includes&lt;/li&gt;
&lt;li&gt;map&lt;/li&gt;
&lt;li&gt;filter&lt;/li&gt;
&lt;li&gt;reduce&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Favor functional map, filter, reduce, forEach, some ect over collection mutation&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Jest&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; group related tests under a describe if multiple tests are in one file such as with tests for utils.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; name test files with suffix tests i.e &lt;code class=&quot;language-text&quot;&gt;utils.test.ts&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor data driven tests with &lt;code class=&quot;language-text&quot;&gt;test.each&lt;/code&gt; over duplicated tests&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1970&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1969&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1950&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;])(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;isDateBefore_1970 returns relevant boolean&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;isDateBefore_1970&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor naming tests in the format &lt;code class=&quot;language-text&quot;&gt;given then should&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;given when then should&lt;/code&gt;. Long test names are perfectly fine.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make it easy to tell apart the &lt;code class=&quot;language-text&quot;&gt;Arrange&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Act&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Assert&lt;/code&gt; sections of your test and in particular to test what the system under test (&lt;code class=&quot;language-text&quot;&gt;sut&lt;/code&gt;) is.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO NOT&lt;/strong&gt; have &lt;code class=&quot;language-text&quot;&gt;magic values&lt;/code&gt; in tests. Simple things like inlining variables to have name can go a long way in test readability.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BAD - why is this value of significance?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the most specific assertions, these give the most specific and useful failure messages as well.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; suppress linting rules, these are in place for a reason. Do consult other developers before suppressing rules, whether for specific code lines, files or entire workspace&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; write tests with a multiple responsibilities, instead a test should have a single focus. Multiple unrelated assertions are a red flag.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; have conditional logic in tests. Rather make data driven tests with theories or separate tests even.&lt;/p&gt;
&lt;h1&gt;GOTCHAS&lt;/h1&gt;
&lt;h2&gt;Jest&lt;/h2&gt;
&lt;p&gt;✨ When setting up a mock with jest.mock, ideally you may want to setup one of the properties bases on a variable so that you can use the same value in you assertions. Jest will however fail the test complaining that mocks cannot access outside variables. This is in place to avoid dirty mocks, however you can by pass this by simply naming the variables with the &lt;code class=&quot;language-text&quot;&gt;mock&lt;/code&gt; suffix i.e &lt;code class=&quot;language-text&quot;&gt;mockUser&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mockUnknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#9E9E9E&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;jest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;../../redux/store&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getState&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RecursivePartial&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RootState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;app:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;statusColors:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;unknown:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mockUnknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[3 Key life lessons Photography has taught me.]]></title><description><![CDATA[Photo by NordWood Themes on Unsplash 3 Key life lessons Photography has taught me. Sometime in 2017, I found myself with plenty of time to…]]></description><link>http://www.drunkonmonads.com/photography-life-lessons/</link><guid isPermaLink="false">http://www.drunkonmonads.com/photography-life-lessons/</guid><pubDate>Mon, 10 Jul 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@nordwood?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;NordWood Themes&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/black-and-gray-film-camera-near-printed-photos-F3Dde_9thd8?utm_content=creditCopyText&amp;utm_medium=referral&amp;utm_source=unsplash&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;3 Key life lessons Photography has taught me.&lt;/h1&gt;
&lt;p&gt;Sometime in 2017, I found myself with plenty of time to spare, bored, tired of routine life and desperately in need of a new hobby. I had always been curious about amateur photography, so I decided to give it a try. I promptly acquired a Canon 1300D (Rebel T6) camera, a popular choice among beginner photographers looking to test the waters without spending a fortune.&lt;/p&gt;
&lt;p&gt;Going in, I somewhat expected this to be much like one of the many other things I tried and eventually lost interest in. Fast forward to some 6 years later, my passion for photography is stronger than ever, and I am further invested in it in many other ways. This pursuit has led my family and me to travel a lot, unashamedly, often motivated by my desire to capture the next great shot.&lt;/p&gt;
&lt;p&gt;My journey through photography has taken me to extraordinary places, some unusual, others scary. It’s been an adventure filled with highs and lows, including navigating a slump during the COVID lockdowns and adjusting to a shift from urban to rural life. But along the way, I’ve acquired lessons that extend far beyond the scope of photography, profoundly influencing my approach to life.&lt;/p&gt;
&lt;h1&gt;Lesson 1 – Balance being in the moment and living the moment.&lt;/h1&gt;
&lt;p&gt;In the early days of photography journey, I was focused on capturing every moment. This often led me to experience life through the lens, detached from the reality around me. While this wasn’t a problem on solo adventures, it became noticeable when traveling with loved ones, especially abroad. I realized that in my quest to capture the perfect moment, I was missing out on creating meaningful memories, and sometimes, even diminishing the experience for others. Decisions like the accumulation of bulky gear didn’t just slow me down; it also impacted those around me.&lt;/p&gt;
&lt;p&gt;I learned the hard way that being present is as important as capturing the moment. This insight applies not just to photography but to life and career. It’s easy to get absorbed in a single task or project, missing out on life’s little joys. Productivity is important, but so is enjoying the journey. Our careers and lives should be more than just a collection of achievements; they should be filled with learning, growth, connections, and personal discoveries.&lt;/p&gt;
&lt;p&gt;It’s easy to become trapped in a single moment. We might get absorbed in a demanding project and miss out on other things, like having lunch with colleagues or attending social events. But in the end, we’re not truly living in the present. While productivity and work are important, it’s equally important to enjoy the journey because there will come a time when what we have missed weighs heavier on us than we anticipated. Perhaps the project was a success, but we realize that the year wasn’t particularly enjoyable, and we did not grow much.
The greatest lesson photography has given to me is the importance of being present. Let’s approach our lives and careers with the wisdom of a seasoned photographer. Let’s focus on our goals, but also be mindful of the journey. Let’s capture the achievements, but also live the experiences.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 642px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b68142e6219b43dcd57e1f0818ebee02/9aabf/Picture1.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 64%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAkEBQj/xAAWAQEBAQAAAAAAAAAAAAAAAAAEBQf/2gAMAwEAAhADEAAAAdzRlMWrM6YYLPEzP//EABoQAAIDAQEAAAAAAAAAAAAAAAQFAgMGABP/2gAIAQEAAQUCXQyvNNPmiKPbBjdRpS0EJvpuRnLK8E7/xAAiEQACAQMEAgMAAAAAAAAAAAABAgMEERIABhMUBXEzYoH/2gAIAQMBAT8Bo9v1r9hKvyCCn607yxUlHAmbcYSI2a3EpmeHlWFwcCzIwddHakd/mx+qoAo9DM2H6fev/8QAHhEAAgICAwEBAAAAAAAAAAAAAgMBBBESAAUHMSL/2gAIAQIBAT8BL0V1myoqfVWMBu5N292Mt1VXXNtkaDJOMjWDFKY0C0bIkaiVmOI9e7G0lVlVe4xb1g5bDv8A6MGRBCU7CBZkZ+SIzHzEc//EACQQAAICAQIGAwEAAAAAAAAAAAIDAQQREzEABRIUISMGIjJR/9oACAEBAAY/AlXaPJUriBMpTe5XN5RwzpNhj3hvNBFOPKtgERj6xHFmmaOYUViQpMvj/K7yg1LBeuLcLRp2ZiVyUYMtKYyyRAsTC10t46zKx8euMexhfpjjbYzJnvOPrH5jbjslDNqLQIelj7Vxfaaw5lcLrPSt0DOMao7ZgonOYRzVlUK1+ndqVhch9rHvgltJYm0tGGDHsUMys5mZmM4wdY2WLBAtM6vctV1aihZ5D2bdeP15/nH/xAAZEAEBAQEBAQAAAAAAAAAAAAABESEAQVH/2gAIAQEAAT8hrccUlEsOQmcpWao8ghfSX0MX7AGmrcemHMSgteF2D6t8UHO3GWq15nH975FepeV3PXkrVkAGG9//2gAMAwEAAgADAAAAEEfP/8QAGBEBAQEBAQAAAAAAAAAAAAAAAREhQVH/2gAIAQMBAT8QMaQys+N8jFQTWjPB/kGXDBT1Kr//xAAXEQEBAQEAAAAAAAAAAAAAAAABEQAx/9oACAECAQE/EBOTGa1nMFMCGuFwEr3AV6wYA//EABgQAQEBAQEAAAAAAAAAAAAAAAERACEx/9oACAEBAAE/EGw6cIdpJC03ohNzsAGCErHORZPAms9RUMUrql5E2opKigZdIMB1+Dfekc8dx5hwymIXqriqv//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Picture1&quot;
        title=&quot;&quot;
        src=&quot;/static/b68142e6219b43dcd57e1f0818ebee02/9aabf/Picture1.jpg&quot;
        srcset=&quot;/static/b68142e6219b43dcd57e1f0818ebee02/953fe/Picture1.jpg 500w,
/static/b68142e6219b43dcd57e1f0818ebee02/9aabf/Picture1.jpg 642w&quot;
        sizes=&quot;(max-width: 642px) 100vw, 642px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;On the day of the shot above, I went too far, dragging a ton of gear up a mountain, including the giant lens which you see my wife being burdened with, and worst of all looking at it all through the lens. The experience could have been a whole lot better in so many ways.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Lesson 2 – Seek for and be open to constructive criticism.&lt;/h1&gt;
&lt;p&gt;Right from the first shot I took, I was excited to share my photographs with others and hear their feedback, especially once I became comfortable using my gear. However, I often found that others didn’t always share my excitement about certain shots. Initially, this was confusing and disheartening, but I gradually understood the critical difference in perspectives. As a photographer, I focused on technicalities, while viewers reacted to the emotions, visual appeal, and stories conveyed. This perspective is significant because award-winning photos are not judged by other photographers, but by the public, many of whom have no detailed knowledge of photography. This realization underlined the importance of diverse perspectives, not just in photography but in life and career.&lt;/p&gt;
&lt;p&gt;Recognizing this important difference made me realize the relevance of other perspectives in my career and life. As someone whose work is overly technical, it is easy to focus on and get absorbed in specific metrics and Key Performance Indicators. However, what I deliver is not viewed in that lens. What truly matters is how my technical expertise translates into meaningful outcomes for others, the clients in particular. The feedback from these diverse groups, who may not understand the intricacies of my work but are the ultimate beneficiaries, is crucial. This experience has made me value the opinions of this group as a key pillar to attaining success.&lt;/p&gt;
&lt;p&gt;I have also observed the same phenomenon in life. There are many situations we encounter, where our perception is influenced by our specific perspective, potentially leading to many biases. When we open ourselves up to the opinions of others, whether they are family, friends, or even strangers, we can learn something interesting.&lt;/p&gt;
&lt;p&gt;I would recommend approaching life in the same way as a seasoned photographer. Be open to criticism, and if anything, seek it out. You will grow as an individual when people honestly review your work, evaluate the situations you are dealing with, or provide feedback on anything in life, for that matter. Any difference in perception is not a setback but a valuable insight.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 709px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8f1afe2c9a06ed0e4a0cab1dedd4e568/be79a/Picture2.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAcFCAn/xAAWAQEBAQAAAAAAAAAAAAAAAAAEBQb/2gAMAwEAAhADEAAAAcsI+rxoYrTFYEX/AP/EABoQAAEFAQAAAAAAAAAAAAAAAAUBAgMEBxD/2gAIAQEAAQUCBFswq17RnO5JXzhHr3//xAAkEQABAwMBCQAAAAAAAAAAAAABAgMRAAQUBRIVQUJTkZKhsf/aAAgBAwEBPwHcjBdU6brUSVcua7sATMBPD7WAnr3Hk2fZaJ7ma//EACIRAQABAwMEAwAAAAAAAAAAAAERAwQhAAIFBhVBUXKBof/aAAgBAgEBPwE6kvCmU9trxYEZOPoTgiWRJfOM67vUctpZz8a5+bbgD6A9Gv/EACUQAAEEAgEBCQAAAAAAAAAAAAECAwQSBREhYQATFCAxQUJxgf/aAAgBAQAGPwJK8ti8/JmJVy1WM5HWOqkymjU+laW69pK2MZnmUK2Y7Tfg+7RwdAlyQXNWr7nSN8kgbs2/IaSfg7E2tP2W3VpP4fJ//8QAGhABAAIDAQAAAAAAAAAAAAAAAREhACAxgf/aAAgBAQABPyEpgKFAW0KVCO5ZBtTjG1DhYGKYW8fEuNUmi/E0/9oADAMBAAIAAwAAABBHH//EABgRAQEBAQEAAAAAAAAAAAAAAAERITEA/9oACAEDAQE/EFz66KLKQAkGoFBi0EAgYVUzFBx1Faq77//EABgRAQEBAQEAAAAAAAAAAAAAAAERIQAx/9oACAECAQE/EBy8NLBUESuVcoUE1Q65UsU8IuAAf//EABkQAQADAQEAAAAAAAAAAAAAAAEAETEhEP/aAAgBAQABPxBiqxvXHe2GYAjMFISBJxxwgJDs70vlkLth2qjVb7//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Picture2&quot;
        title=&quot;&quot;
        src=&quot;/static/8f1afe2c9a06ed0e4a0cab1dedd4e568/be79a/Picture2.jpg&quot;
        srcset=&quot;/static/8f1afe2c9a06ed0e4a0cab1dedd4e568/953fe/Picture2.jpg 500w,
/static/8f1afe2c9a06ed0e4a0cab1dedd4e568/be79a/Picture2.jpg 709w&quot;
        sizes=&quot;(max-width: 709px) 100vw, 709px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 697px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/11e84f1fb761fcf1a14ad47e88302133/0c205/Picture3.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.39999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAcKCAn/xAAWAQEBAQAAAAAAAAAAAAAAAAAAAgP/2gAMAwEAAhADEAAAAdoJrjKmGdaRMWQ//8QAGhAAAgMBAQAAAAAAAAAAAAAAAgUEBgcBA//aAAgBAQABBQJcqbnHfOxTWKDXYxx2W2aa1We1tscgi2zVi7//xAAeEQABAgcBAAAAAAAAAAAAAAABAAIDEhMxUYGh0f/aAAgBAwEBPwGjDFg7bj6pBjpX/8QAIBEAAQIFBQAAAAAAAAAAAAAAAgABAwQTFDJTcXKR0f/aAAgBAgEBPwG7mHyIW4gPiqxNR+tl/8QAKBAAAgIABQMCBwAAAAAAAAAAAQMCBAAFBhESEyEiFFIjMTJhcnOh/9oACAEBAAY/Ai9lq/H4ZJPSKyI7b+bWtkFw90yNgO5+WNBZRmas4ba1VeuDKTl9jJryrEoU/Tr2e19WPlYuQVE/STyAJl2wDYZm1BnKQKHOpif57Uy9Pl+zl7hizlFzUzjRuKbXsrTWq15sQ2PCSuspQYuPDeI6Uly2lIGUgcacm3N7c56RUpOm5bwicoUixG0mFXhCOwW+EZgs6kjxEZGUe2NzrrPt/syoP4KgGP/EABsQAQEAAwADAAAAAAAAAAAAAAERACExQXHw/9oACAEBAAE/IWp9AcTgBPT4h25cAxx1TTp9CPBQZo9CxqkXUNXzNugW9dOzeTNNYGYWUD5AFyjvOxfmcz//2gAMAwEAAgADAAAAEIP/AP/EABwRAQACAgMBAAAAAAAAAAAAAAEhMRFhAEFR8f/aAAgBAwEBPxAECQpz6DMOb7tWea/y1p799j//xAAbEQEBAQACAwAAAAAAAAAAAAABESEAMVFhof/aAAgBAgEBPxDSpOpJkhUMoPVyWKcXVbLXHevHr7z/xAAYEAEAAwEAAAAAAAAAAAAAAAABABEhQf/aAAgBAQABPxCrgErEqsV3US0Gvu9kqqC0jIMhl9fNAhzWZYwESYYmIXIiJk979JVfdMCJPctuOqdqrgzXmuz/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Picture3&quot;
        title=&quot;&quot;
        src=&quot;/static/11e84f1fb761fcf1a14ad47e88302133/0c205/Picture3.jpg&quot;
        srcset=&quot;/static/11e84f1fb761fcf1a14ad47e88302133/953fe/Picture3.jpg 500w,
/static/11e84f1fb761fcf1a14ad47e88302133/0c205/Picture3.jpg 697w&quot;
        sizes=&quot;(max-width: 697px) 100vw, 697px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 492px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/4fab26be6d87f05aafc3f98cd400e838/aee3f/Picture4.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.66666666666666%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAcCBgj/xAAWAQEBAQAAAAAAAAAAAAAAAAAHAAL/2gAMAwEAAhADEAAAAc1MGVrRD9YjINX/xAAaEAACAwEBAAAAAAAAAAAAAAABBQIDBAYT/9oACAEBAAEFAsrjnQF+3n2G5xLArYL7rjO2s2mzzE//xAAgEQABAwUBAAMAAAAAAAAAAAACAQMEBRITISIRADEy/9oACAEDAQE/AaTBpJVOEk6Lkik8iSAU3Oml0XmHE5d92WmPh2qq2ovyVEoaSpCMRZAM53cQ5/y1fwPTbhaHxOjMtbJV2v8A/8QAIREAAQMEAgMBAAAAAAAAAAAAAgEDBAUREhMUIgAVITL/2gAIAQIBAT8Bq8uqJSZ/r5ZMzUjmsVwRauD6WVtV5DbzKii2zQ2zQgyS2VvIciscSNyJTLkjjs73NH7d1jsPobQJkd16Ntj96gKfPP/EACgQAAIABAQGAgMAAAAAAAAAAAECAwQREgAhMVETFCIjMoEFQUShwf/aAAgBAQAGPwIVmZoafgTP9Ar6riB8fzkeU5i5RNzMrESVR6VQMRe5DUK9K1vaHopZljyMQzkw0K3vSspxIMQOgcFW4gOjUYEZMCMKt/Tr4i7L6r4n2ldsS3MFY6tGqEaGtosUkb3Z6V02ywexL50J7EPYbKB+sf/EABwQAQEBAAMAAwAAAAAAAAAAAAERIQAxQVFxgf/aAAgBAQABPyHeOoEF+htdEK5vNRr8OazDbzE5s/kWUbf1AAHZyqk9DI+mog72D0cAo3KE2loCrCiUHg1RoIKpV2s7/XP/2gAMAwEAAgADAAAAEJ8P/8QAGBEBAQEBAQAAAAAAAAAAAAAAAREhADH/2gAIAQMBAT8QDs/nDTxYaJUAKUig7pO3l+iaaeP/xAAWEQEBAQAAAAAAAAAAAAAAAAABESH/2gAIAQIBAT8QZoHFoKprOEWpWt4hBmxJBgsAIf/EABkQAQEBAQEBAAAAAAAAAAAAAAERACExQf/aAAgBAQABPxAZ4hx3oh5knh9NwdNFZZBIgevkTFKRU45t3xBwCUZ7m1KuaWhAYY7RUTikYaYXCpQddrhQEGgL6lq//9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Picture4&quot;
        title=&quot;&quot;
        src=&quot;/static/4fab26be6d87f05aafc3f98cd400e838/aee3f/Picture4.jpg&quot;
        srcset=&quot;/static/4fab26be6d87f05aafc3f98cd400e838/aee3f/Picture4.jpg 492w&quot;
        sizes=&quot;(max-width: 492px) 100vw, 492px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Silhouettes as shown in the 1st two shots, are a technique I enjoy a lot and one I will go out of my way to get. I waited in the same position for over an hour to get that first shot. However, the images that often make an impression on others are the ones that evoke some emotions, much like the last one which usually happens in a split moment, are captured hastily, and do not require much technical finesse to get right. While I continue to shoot what I like and enjoy when I am out to get impressions, I know what my audience likes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Lesson 3 – Go out of your way on preparation and embrace unpredictability.&lt;/h1&gt;
&lt;p&gt;The third and final key lesson was particularly tough for me to learn, as I had to learn it the hard way. Throughout my photography journey, there have been many off days that could have been avoided if I had been a little more prepared. Missing out on shots due to uncharged batteries or forgotten tripods and memory cards, or perhaps not checking the weather, has all been frustrating. Then the time came when I was more prepared for what I knew and expected, but it all changed on the day or in the moment of the shot.&lt;/p&gt;
&lt;p&gt;It has been a tough lesson, but over time, what I needed to do better clicked. Now, when I have an important shot or when my family and I are travelling, I have a checklist. I know exactly what I need to bring. I don’t bring all my gear, but I always refer to the checklist. I will consider the area we’re going to, the type of photography I’ll be doing, the sunrise and sunset times, the weather, the distances we’ll need to travel and more.&lt;/p&gt;
&lt;p&gt;This lesson applies to so many aspects of life and career. The preparation, however, is only half the story. With photography, there lies the ability to adapt to the unexpected: a sudden change in weather, or a spontaneous moment. These unpredictable elements often transform a good photographer into a great one. In our professional and life endeavors, we often equate success with planning – setting clear goals, strategizing, and methodically working towards our objectives. While this is the first part of the lesson and a key thing, the unpredictable nature of the world often throws us curveballs and must be acknowledged. Trends shift, new technologies emerge/deprecate, relationships evolve, and unforeseen challenges arise. The ability to adapt, pivot our strategies, and embrace change is what often separates those who are resilient from those who aren’t.&lt;/p&gt;
&lt;p&gt;As we walk the path of life/careers, let us be like the photographer who sets up their camera with care but is always ready to capture an unplanned, perfect shot. Let’s prepare for the future, but also stay open and adaptable to the unforeseen twists and turns of life. Embracing this balance is the key to not just surviving but thriving in the unpredictable journey of life.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 626px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5e73736a3a6b839a4b0313401027c4a6/ce661/Picture5.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 63.800000000000004%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACmUlEQVR42j1TyU5iQRR9H+KWrSvZuzQYI8QYjAFFCCBqVJyVeZDJCVFRMO613ko/wm5Cp/t7tN7L7XPKwKJS9Wo4073PWlhYqAWDwfeVlZXXtbU1tbu7q0qlksrn86parapWq6UuLi5Uo9FQiURCZbNZdX5+bubDw0O1sbGhotHoaygUel9aWmpYy8vLQ1wUHLj7+/uCi3J2dibNZlM6nY70+315enqSx8dHOTk5kaurK+l2u3J5eSkgExDL3t6eu7OzI7FY7C8Bf6VSKW5+A8gBqwNgp1gsOlBoRrlcdgDkHB0dOSB0oNC5vb11crmcUygUOH/jjKIGFmwODg4OqMrFY6OMzLBpZtiXSqUi19fXsr6+Ll6vVyYnJ2V+fl4WFxfNWa1Wc0EqwBlasDugRWy4I5ucaR0qzRiRIGeZmpoSj8cjExMTMjMzI/V6neQuI8hkMkOLMvkINgzgzc2NnJ6eCoojVEwgFMQoRkaC8IURcZ6enpatrS2TITFgfWhtb28PKBuPDSCZkIsZ/GYRuIfMJJ1O87GZHx4eZHNzU+bm5gQFcSHsRyGUGEBa5kOqIhvXtN9ut01+BEwmk0YRSe7v783w+/0SCARcCjg+Pv4BBDJBXFobKeNltgeVcM22YWuQ4OXlxewxHr7x+XwuY0BUQwuLcZUJTLW8SEV3d3djJQRESxlArqma+ZIc+y6rjjiG1urq6ifbAUq/IFmjOBqXNGxpWNYANQNKNYg1ADWUaxBruNJoKw1lX8wWOL8t9NIfVo/BUiH7CX01zolqer2ePD8/mz+FEfDvoVV2A1sOYlwWKh6P/7NmZ2fr+Fs+0I9vYLARuo1DG49tKLBRJBu9ZkO1zXN+c/AcVbYjkYgNl2/hcPgDOI3/WJhkly661jEAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Picture5&quot;
        title=&quot;&quot;
        src=&quot;/static/5e73736a3a6b839a4b0313401027c4a6/ce661/Picture5.png&quot;
        srcset=&quot;/static/5e73736a3a6b839a4b0313401027c4a6/0eb09/Picture5.png 500w,
/static/5e73736a3a6b839a4b0313401027c4a6/ce661/Picture5.png 626w&quot;
        sizes=&quot;(max-width: 626px) 100vw, 626px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You need to have all the conditions just right as a photographer to take that one great shot. You need the gear, lighting, camera settings and many other variables to be just right that need preparation. When working with a subject like a dragonfly that only gives you a second or so to work with, preparation and adaptability are everything.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;My photography journey has taught me more than just these three lessons. Knowing your tools intimately, stepping out of your comfort zone, valuing your unique journey, avoiding dogmatism about tools or methods, sharing knowledge generously, seeking community and support, and above all, having fun are equally important. These principles, derived from photography but are applicable to every facet of life.&lt;/p&gt;
&lt;p&gt;Photography has been more than a hobby; it’s been a journey of discovery and learning. It’s taught me to view life through various lenses, both literally and metaphorically. As I continue to explore the world through my camera, I’m reminded that life, like photography, is about the journey and the experiences, not just the outcomes. These lessons encourage a fulfilling and adaptive approach to life’s challenges and opportunities. Let’s navigate our paths with the curiosity of a photographer, prepared yet adaptable, ready to capture life’s unexpected beauty.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Web API Conventions]]></title><description><![CDATA[Photo by Brian McGowan on Unsplash ASP.NET Core Web API Conventions ASP.NET Core Web API conventions are a set of guidelines that help…]]></description><link>http://www.drunkonmonads.com/web-api-conventions/</link><guid isPermaLink="false">http://www.drunkonmonads.com/web-api-conventions/</guid><pubDate>Fri, 12 May 2023 19:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@sushioutlaw?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Brian McGowan&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/LObpG0ku8VM?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;ASP.NET Core Web API Conventions&lt;/h1&gt;
&lt;p&gt;ASP.NET Core Web API conventions are a set of guidelines that help standardize the most common return types, status codes, and parameters for specific types of actions. Conventions are useful for enhancing the understandability and usability of your API. Moreover, they help to create uniform API documentation, especially when using tools like Swagger.&lt;/p&gt;
&lt;h2&gt;Using Conventions&lt;/h2&gt;
&lt;p&gt;To use conventions, you need to create a class that inherits from the ApiConventions class. This class will contain the definitions for your conventions. For example, you could create a convention for the Get action that always returns a 200 OK status code and a JSON object.&lt;/p&gt;
&lt;p&gt;Once you have created your convention class, you need to register it with the API. This can be done in the ConfigureServices method of your Startup class.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddMvc&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Conventions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MyConventions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;assembly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApiConventionType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MyConventions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Alternatively, you can apply this at an assembly level:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;assembly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApiConventionType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MyConventions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Controller level:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApiConventionType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DefaultApiConventions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ContactsConventionController&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ControllerBase&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And Controller action level:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpPut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;{id}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApiConventionMethod&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DefaultApiConventions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                     &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DefaultApiConventions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Put&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IActionResult&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Update&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Contact&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;contact&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once you have registered your conventions, they will be applied to all actions that match the criteria you defined.&lt;/p&gt;
&lt;p&gt;Conventions in ASP.NET Core Web API can help you define:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The return type of an action&lt;/li&gt;
&lt;li&gt;The status code of an action&lt;/li&gt;
&lt;li&gt;The parameters of an action&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To define the return type and status code of an action, you use the &lt;code class=&quot;language-text&quot;&gt;[ProducesResponseType]&lt;/code&gt; attribute. For example, the following attribute defines the &lt;code class=&quot;language-text&quot;&gt;Get&lt;/code&gt; action to return a JSON object with a 200 status code:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ProducesResponseType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;StatusCodes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Status200OK&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MyObject&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MyObject&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To define the parameters of an action, you use the &lt;code class=&quot;language-text&quot;&gt;[ApiConventionNameMatch]&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;[ApiConventionTypeMatch]&lt;/code&gt; attributes. For example, the following attribute defines the GetById action to take an id parameter:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApiConventionNameMatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ApiConventionNameMatchBehavior&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Suffix&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApiConventionTypeMatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ApiConventionTypeMatchBehavior&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MyObject&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetById&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApiConventionNameMatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ApiConventionNameMatchBehavior&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Suffix&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApiConventionTypeMatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ApiConventionTypeMatchBehavior&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MyObject&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetById&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Benefits of Using Conventions&lt;/h2&gt;
&lt;p&gt;There are several benefits to using conventions in ASP.NET Core Web API:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Standardization: Conventions can help you to standardize your API, making it easier to understand and use.&lt;/li&gt;
&lt;li&gt;Reusability: Conventions can be reused across multiple actions, making your code more concise and easier to maintain.&lt;/li&gt;
&lt;li&gt;Documentation: Conventions can be used to generate documentation for your API, making it easier for users to understand how to use it.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Default Conventions&lt;/h2&gt;
&lt;p&gt;ASP.NET Core Web API includes a set of default conventions that can be used to define the return type, status code, and parameters of common actions. These conventions are defined in the DefaultApiConventions class.&lt;/p&gt;
&lt;p&gt;The following table shows the default conventions for the most common actions:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Action&lt;/th&gt;
&lt;th&gt;Return Type&lt;/th&gt;
&lt;th&gt;Status Codes&lt;/th&gt;
&lt;th&gt;Parameters&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Get&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;IEnumerable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;200&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;404&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Post&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;object&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;201&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;400&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;object&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Put&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;object&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;200&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;404&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;400&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;object&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Delete&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;void&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;200&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;404&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;400&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;int&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;object&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;201&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;400&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;object&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Edit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;void&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;204&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;404&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;400&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;int&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;object&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Find&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;IEnumerable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;200&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;404&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;object&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;Update&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;void&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;204&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;404&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;400&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code class=&quot;language-text&quot;&gt;int&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;object&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;ASP.NET Core Web API conventions are a powerful tool that can significantly improve the quality and maintainability of your API. They ensure standardization, promote reusability and facilitate the automatic generation of API documentation. By using conventions, you can make your API more understandable and easier to use. If you’re not already using them, it’s certainly worth giving them a try.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Dependency injection with Scrutor]]></title><description><![CDATA[Photo by Mick Haupt on Unsplash Dependency injection Dependency injection is a key concept in modern software development, as it allows…]]></description><link>http://www.drunkonmonads.com/dependency-injection-scrutor/</link><guid isPermaLink="false">http://www.drunkonmonads.com/dependency-injection-scrutor/</guid><pubDate>Mon, 01 May 2023 19:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/ko/@rocinante_11?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Mick Haupt&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/eQ2Z9ay9Wws?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Dependency injection&lt;/h1&gt;
&lt;p&gt;Dependency injection is a key concept in modern software development, as it allows developers to write code that is modular, testable, and easy to maintain. &lt;code class=&quot;language-text&quot;&gt;Microsoft.Extensions.DependencyInjection&lt;/code&gt; is a popular DI container in the .NET ecosystem, which allows developers to register dependencies and resolve them at runtime. However, as projects grow in size and complexity, managing all the dependencies can become challenging.&lt;/p&gt;
&lt;p&gt;That’s where &lt;code class=&quot;language-text&quot;&gt;Scrutor&lt;/code&gt; comes in. Scrutor is a library that complements &lt;code class=&quot;language-text&quot;&gt;Microsoft.Extensions.DependencyInjection&lt;/code&gt;, providing additional features for scanning and registering dependencies. It allows developers to scan assemblies and register dependencies based on naming conventions, interfaces, and attributes, reducing the amount of boilerplate code required for DI configuration. In this article, we’ll explore some of the benefits of using Scrutor and show code examples of how it can be used to improve the dependency injection experience.&lt;/p&gt;
&lt;h1&gt;Scanning for Dependencies with Scrutor&lt;/h1&gt;
&lt;p&gt;Let’s start by looking at an example of registering dependencies without Scrutor&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddScoped&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IRegistrationService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RegistrationService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RedisHealthCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SqlDbHealthCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AzureServiceBusHealthCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a straightforward approach to registering dependencies, but it can become cumbersome as the number of dependencies grows. Additionally, if a new dependency is added to the project, it needs to be manually registered with the container, for example, if we were to introduce more implementations of health checks we would need to remember to include them manually.&lt;/p&gt;
&lt;p&gt;With Scrutor, we can simplify this process by &lt;code class=&quot;language-text&quot;&gt;scanning&lt;/code&gt; for dependencies based on naming conventions or attributes. For example, we can scan all assemblies in the current application domain and register all classes that implement an interface with a given name&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Scan&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scan&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FromAssemblyOf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IHealthCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddClasses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;classes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;classes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AssignableTo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IHealthCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsSelf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithSingletonLifetime&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;FromAssembliesOf&lt;/code&gt; method specifies which assemblies to scan, and the &lt;code class=&quot;language-text&quot;&gt;AddClasses&lt;/code&gt; method specifies which classes to include in the scan. The &lt;code class=&quot;language-text&quot;&gt;AsSelf&lt;/code&gt; method tells Scrutor to register each concrete class as itself, and the &lt;code class=&quot;language-text&quot;&gt;WithSingletonLifetime&lt;/code&gt; method sets the lifetime of each dependency to scoped.&lt;/p&gt;
&lt;p&gt;You can also use the following registrations&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;As(params Type[] types)&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;As(IEnumerable&amp;lt;Type&gt; types)&lt;/code&gt;: Registers each matching concrete type as each of the specified types&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;As&amp;lt;T&gt;()&lt;/code&gt;: Registers each matching concrete type as &lt;code class=&quot;language-text&quot;&gt;T&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AsImplementedInterfaces()&lt;/code&gt;: Registers each matching concrete type as all of its implemented interfaces&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AsImplementedInterfaces(Func&amp;lt;Type, bool&gt; predicate)&lt;/code&gt;: Registers each matching concrete type as all of its implemented interfaces, with a predicate to filter which interfaces to register&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AsMatchingInterface()&lt;/code&gt;: Registers the type with the first found matching interface name&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AsMatchingInterface(Action&amp;lt;Type, IImplementationTypeFilter&gt; action)&lt;/code&gt;: Registers the type with the first found matching interface name with a filter for the matching type&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;As(Func&amp;lt;Type, IEnumerable&amp;lt;Type&gt;&gt; selector)&lt;/code&gt;: Registers each matching concrete type as each of the types returned from the func&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;UsingAttributes()&lt;/code&gt;: Registers each matching concrete type according to their definition of a &lt;code class=&quot;language-text&quot;&gt;ServiceDescriptorAttribute&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All the scopes supported by &lt;code class=&quot;language-text&quot;&gt;Microsoft.Extensions.DependencyInjection&lt;/code&gt; are available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;WithSingletonLifetime()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;WithScopedLifetime()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;WithTransientLifetime()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;WithLifetime()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are multiple ways to add classes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AddClasses()&lt;/code&gt;: Adds all public, non-abstract classes from the selected assemblies&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AddClasses(bool publicOnly)&lt;/code&gt;: Adds all public, non-abstract classes from the selected assemblies with a boolean on whether to add public types only&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AddClasses(Action&amp;lt;IImplementationTypeFilter&gt; action)&lt;/code&gt;: Adds all public, non-abstract classes from the selected assemblies that match the requirements specified in the filtering action&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;AddClasses(Action&amp;lt;IImplementationTypeFilter&gt; action, bool publicOnly)&lt;/code&gt;: Adds all public, non-abstract classes from the selected assemblies that match the requirements specified in the filtering action with a boolean on whether to add public types only&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are also multiple ways to target and assembly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;FromCallingAssembly()&lt;/code&gt;: Scans for types from the calling assembly&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;FromExecutingAssembly()&lt;/code&gt;: Scans for types from the currently executing assembly&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;FromEntryAssembly()&lt;/code&gt;: Scans for types from the entry assembly&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;FromApplicationDependencies()&lt;/code&gt;: Will load and scan all runtime libraries referenced by the currently executing application. Calling this method is equivalent to calling &lt;code class=&quot;language-text&quot;&gt;FromDependencyContext(DependencyContext)&lt;/code&gt; and passing in &lt;code class=&quot;language-text&quot;&gt;DependencyContext.Default&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;FromApplicationDependencies(Func&amp;lt;Assembly, bool&gt; predicate)&lt;/code&gt;: Will load and scan all runtime libraries referenced by the currently executing application with a predicate filter. Calling this method is equivalent to calling &lt;code class=&quot;language-text&quot;&gt;FromDependencyContext(DependencyContext)&lt;/code&gt; and passing in &lt;code class=&quot;language-text&quot;&gt;DependencyContext.Default&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;FromAssemblyDependencies(Assembly assembly)&lt;/code&gt;: Will load and scan all runtime libraries referenced by the specified assembly&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;FromDependencyContext(DependencyContext context)&lt;/code&gt;: Will load and scan all runtime libraries in the given &lt;code class=&quot;language-text&quot;&gt;DependencyContext&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;FromDependencyContext(DependencyContext context, Func&amp;lt;Assembly, bool&gt; predicate)&lt;/code&gt;: Will load and scan all runtime libraries in the given &lt;code class=&quot;language-text&quot;&gt;DependencyContext&lt;/code&gt; with a filter predicate&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;FromAssemblyOf&amp;lt;T&gt;()&lt;/code&gt;:  Will scan for types from the assembly of &lt;code class=&quot;language-text&quot;&gt;T&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;FromAssemblyOf(params Type[] types)&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;FomAssembliesOf(IEnumerable&amp;lt;Type&gt; types)&lt;/code&gt;:  Will scan for types from the assemblies of each passed-in type&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;FromAssemblies(params Assembly[] assemblies)&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;FromAssemblies(IEnumerable&amp;lt;Assembly&gt; assemblies)&lt;/code&gt;:  Will scan for types from each passed in assembly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By using Scrutor to scan for dependencies, we can reduce the amount of boilerplate code required for DI configuration and ensure that all dependencies are automatically registered with the container.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Scrutor means to explore/scan/search carefully, search into or out, examine thoroughly, explore a thing, investigate to scrutinize.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Open Generics&lt;/h1&gt;
&lt;p&gt;Scrutor also supports registering open generic types. For example, let’s say we have an interface &lt;code class=&quot;language-text&quot;&gt;IFoo&amp;lt;T&gt;&lt;/code&gt; and a class &lt;code class=&quot;language-text&quot;&gt;Foo&amp;lt;T&gt;&lt;/code&gt; that implements it&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IFoo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; { }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IFoo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; { }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We can register all implementations of &lt;code class=&quot;language-text&quot;&gt;IFoo&amp;lt;T&gt;&lt;/code&gt; using the &lt;code class=&quot;language-text&quot;&gt;AddClasses&lt;/code&gt; method with the &lt;code class=&quot;language-text&quot;&gt;AssignableTo&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;AsImplementedInterfaces&lt;/code&gt; methods, like so:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Scan&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scan&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scan&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FromAssemblyOf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddClasses&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;classes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;classes&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AssignableTo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IFoo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&amp;gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsImplementedInterfaces&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Decorators with Scrutor&lt;/h1&gt;
&lt;p&gt;Another powerful feature of Scrutor is the ability to use decorators to modify or replace registered dependencies. For example, let’s say we have an existing service that we want to enhance with additional functionality. We can do this by registering a decorator that wraps the existing service&lt;/p&gt;
&lt;p&gt;Let’s say we have an existing health check implementation:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MyHealthCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IHealthCheck&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HealthCheckResult&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CheckHealthAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HealthCheckContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Perform health check logic here&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We want to add logging to this health check without modifying the original code. We can do this by registering a decorator that wraps the existing health check:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Decorate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IHealthCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;serviceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;LoggingHealthCheckDecorator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;check&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;Decorate&lt;/code&gt; method takes a delegate that creates the decorator instance, passing in the existing health check and the service provider. The decorator can then modify or replace the existing health check as needed.&lt;/p&gt;
&lt;p&gt;Here’s an example of what the &lt;code class=&quot;language-text&quot;&gt;LoggingHealthCheckDecorator&lt;/code&gt; might look like:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;LoggingHealthCheckDecorator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IHealthCheck&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IHealthCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_innerCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ILogger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;LoggingHealthCheckDecorator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;LoggingHealthCheckDecorator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IHealthCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;innerCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ILogger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;LoggingHealthCheckDecorator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_innerCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;innerCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HealthCheckResult&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CheckHealthAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HealthCheckContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Checking health&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_innerCheck&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CheckHealthAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Health check result: {Result}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Status&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By using decorators with Scrutor, we can easily enhance or replace existing dependencies without modifying the original code.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Scrutor is a powerful library that complements &lt;code class=&quot;language-text&quot;&gt;Microsoft.Extensions.DependencyInjection&lt;/code&gt; by providing additional features for scanning and registering dependencies. With Scrutor, we can simplify the DI configuration process and ensure that our code remains modular, testable, and easy to maintain.&lt;/p&gt;
&lt;p&gt;By leveraging the power of Scrutor, we can write cleaner, more maintainable code and spend less time managing dependencies.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Effective Git Management Guide]]></title><description><![CDATA[Photo by Yancy Min on Unsplash Effective Git Management Guide Commits ✅ DO push your commits often, in case Murphy (Murphy’s Law) decides to…]]></description><link>http://www.drunkonmonads.com/effective-git-management/</link><guid isPermaLink="false">http://www.drunkonmonads.com/effective-git-management/</guid><pubDate>Sat, 01 Apr 2023 19:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@yancymin?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Yancy Min&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/842ofHC6MaI?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Effective Git Management Guide&lt;/h1&gt;
&lt;h2&gt;Commits&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; push your commits often, in case &lt;strong&gt;Murphy&lt;/strong&gt; &lt;em&gt;(Murphy’s Law)&lt;/em&gt; decides to visit.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; break your work into smaller, logical pieces as commits.&lt;/p&gt;
&lt;p&gt;This helps with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Making it possible to cherry-pick and revert specific changes&lt;/li&gt;
&lt;li&gt;Making &lt;code class=&quot;language-text&quot;&gt;git blame&lt;/code&gt; easier when trying to track a change, especially around bug fixes, which will then tie nicely with a matching commit message&lt;/li&gt;
&lt;li&gt;Making it possible to review code by commits which can be useful for large Pull Requests&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, this approach helps maintain a clean and understandable commit history, making it easier to track the origin of changes and simplifying the review process.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure each commit makes a single, focused change.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use clear and descriptive commit messages that explain the purpose and effect of the change.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the imperative verbs/mood in the subject line. Use a consistent style for your commits, such as starting with a verb and using the present tense.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 372px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/bd31e93181709641e0f7e3d661eec5fa/448ef/bad-commit-messages.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 96.77419354838709%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAATCAYAAACQjC21AAAACXBIWXMAAAsSAAALEgHS3X78AAADSUlEQVR42pWTbUhTURjHj069boqarynSIq5LdL7PqfRhUJDRh8JqJYWSSH0JQ0WiDNuXiCDoUwh+iKlpynXqtjbn7t1wzrlrdH3BV9BtV29KVhYoBH3J2znO5dusfOC597nPec7vnOd/zwFgrwWgh0wmkxYVSVLl8ozkrKz89Ly8vNScnBxxZmamBMX5+fnZcrk8GRxuK7EAfJGEhHxMAYDHFIrE2OTk5xk4XhFXUCBNyM7OjoOgSKlUmgDBSXDB02lpadGH4jBs7UVu7g9eIvn+E4Cv57y5zx1CoacAxThehUFgsEKhCEKuVCoF6BvHccznYrE4FJYG+XZ44tixb0UREWtyuEPRxgYT29mpam5sLIlHoyoVCNyWY78fNFTM88j5rQKOI6JNJm3tzEzWM5iPRDk0vv0OQO6LdzP8oL1Ap5OIZpjFxKUlUO5yhcXvn/xPm54GaTYbKKFpcHF0FFxyucAWxO0OrGRZULi8DGJgLm96OiKa4wAOY+n4OIjyeEAWdDHLio4vLIBcpRIItmSYnQVPDQbwS6sFn+x2sAEnnEVAmo48CeOKpaXwerc71AThpSwb0+xyBbzmuLCbHk8UCUH1i4tB99xurFuliguH0wLBygoQwZZi19dBDHKGAcF/ROB5gcVirqSol6ecTg7v69PcRXmz2VlCku3FKLZaHeftdvUFr5aqg1r6fg7Pb2JTU33VRqP6DMsyqSTZ8sRsbg2j6XelXV2v7qCaDx90lynqTRVB8AK/eu7A+JDhYe39yUlSNjFBSYaH9XU8z4YODemUDkf3LVQzN0cmUVRnOUEQIYfAvNvd3JzHLBaiWqdTF46NkSkURTxEsNFR0xUIuOW7omjx7RYD/JzFHZjV2lXT09NSxHFO3OHQPYDHSDgy8u6a1aop233f/cR7k6hNm01TazC0FqA2+/s7HqMc3G2pydRR9jeAn3YZkd2urRkcJOTv3xslvb0tDU1NKhHSzGhsL9+t738ZnJhOkm9lDNOf2t2tbtDrm0RQuxt6fUvZkW+Kb2WGMWb09DQ/gndZSNP6q3p929FhPltdpRMMhra6gQF1lM3WdV2jUd/etdjRgfPzfRg8T0L4jhgc7C2GscB7NI4O+w1Y7ZiQm8wuBQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;bad-commit-messages.png&quot;
        title=&quot;&quot;
        src=&quot;/static/bd31e93181709641e0f7e3d661eec5fa/448ef/bad-commit-messages.png&quot;
        srcset=&quot;/static/bd31e93181709641e0f7e3d661eec5fa/448ef/bad-commit-messages.png 372w&quot;
        sizes=&quot;(max-width: 372px) 100vw, 372px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 372px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/52398b1f850196cc4f6db1f6671d5065/448ef/good-commit-messages.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 97.8494623655914%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsSAAALEgHS3X78AAADZUlEQVR42pWTW0wTQRSGpy0XuakhKiBaEAoEBGktF0FSjA8kiryY9MGYeCHRiCYmCpWIwOqLT0p80QT0AbsKZaHttpJegLJcAzSFNoTEBFoEU2wICLzp23qm2xUk5eJJTubMmdlv5j9zFqFtplQqRcXFxcdlsqIkqVR6NC8v76RcLheDJ+Tn58cXFBScwLnc3NxE2C5EwY0VcM4B5fLTqQpFZlphYXacTCaTACwVxuMYBIekQXwGcjmwXRAUFxOz2iGVbqyJxWtzCC1LuOzvt2Fh3nQcyeV3Q0tLS0OwB24lxHFWVlYYdolEEo4dDgn1fxod/VOZk7NRm5i49hChtUOrq6aD9fVqTUXF+zi8vhWEFWDHMUEQOCfYNgZEs9z1WXYmuq9PU72wUPIGcmFb1/7LWJarod3+JdtmoxWLi+jGzMzBWJwjCCRkGBQCYCGOm5tRKD6EopAI5/+p5ewsCofFCN7xBzjv9aKqpSV0JHDDEG4khBjCxUoRf3OGKd2ETk4i2mBAv8xmtDw2hnw/fqBMnHc4RBfdbqHq2zdUDU673ejWwoLgtceD2mB+DRSo5+ZQE8SQRwabLTzVD5yeRpcBds9iQZV2O7q9vo4O8+2DJU5O1lVOT1+4zrJPjzqdT154vaEyu70pZXT05ktYj3e5XpU4nVef8SqCGsMQ/sXxcWsZTXfegfpGQF0faTTafBx3dpINLS26dI/HI7ZY9LVqtfvY33fgC7vpHGxoSHfFZPpcxbKOSIahVDpdawHugOFhbQPDGCQ+H5M8NKStMxja4rY+6raXpvwFHxzUlhuNH+9j2OCgvqavjwKYK8psbn9O02TG169MMhzWaDaTCVwXEMJgbSPkb8bBsExKRZIt5yCO7O/vaiTJdxlLSw6xydRGmM3aXWH+605NWS8ZjeoHLPs9YmSEVlHUhyIMs1rbn2PY/LwtaWCgq3Fiojt+RxjfP05ndzkHYyOGh/XVNK0u9PlcUSC/wWQisxwOXWpPj4aAecJuMBR4zVM2W2clBoC0aoiLV1ZGYqzWDoC1yfAeyJV1d39O2RPGy4XxAEhT0XSrAs/hNXONRvJsEIBgH/+xK4phtDU0/UnBN/V2QODgvWEOhzGyt5d6DFLP4zlFUSIesKu0ncxioWL1+k85e9Zmn/YHdGXQt45PEuIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;good-commit-messages.png&quot;
        title=&quot;&quot;
        src=&quot;/static/52398b1f850196cc4f6db1f6671d5065/448ef/good-commit-messages.png&quot;
        srcset=&quot;/static/52398b1f850196cc4f6db1f6671d5065/448ef/good-commit-messages.png 372w&quot;
        sizes=&quot;(max-width: 372px) 100vw, 372px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The idea is that instead of a commit message saying what has been done, it should be read as this is what will happen when the commit is applied. Commit messages should read like chapters in a book, the book being the unit of work that will result in a Pull Request.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Branches Management&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use a well-defined branching strategy like GitFlow or GitHub Flow to manage the development process effectively and keep the main branch stable.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; protect critical branches (e.g., main or develop) by applying branch protection rules, such as requiring PR reviews and passing CI checks before merging.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use branch prefixes, starting with the name of the committer, a change type like feature, and preferably a task code if you have a tracking system, i.e. &lt;code class=&quot;language-text&quot;&gt;john\feature\128952&lt;/code&gt;. Most git visual tools will create a hierarchy out of this which makes it easy to navigate and filter, especially at the contributor level.&lt;/p&gt;
&lt;p&gt;Examples of useful branch prefixes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;feature&lt;/code&gt;: Introduces a new feature&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;bug&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;fix&lt;/code&gt;: Addresses a bug&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;boyscout&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;chore&lt;/code&gt;: Performs a change not related to features of fixes such as code formatting, updated dependencies etc. You can also get more granular, i.e. with &lt;code class=&quot;language-text&quot;&gt;format&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;updates&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;style&lt;/code&gt; etc.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;refactor&lt;/code&gt;: Code specific chore or boy scout&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;doc&lt;/code&gt;: A contribution to documentation&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;test&lt;/code&gt;: Introduces new test coverage or updates existing tests&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ci&lt;/code&gt;: Changes related to CI artefacts&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;When it comes to reverts, generally it is better to retain the default message provided by git as there is a lot of context that can be lost by omitting it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; clean up remote branches after they are merged to keep the repository clean and organized.&lt;/p&gt;
&lt;h2&gt;Pull Requests&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider PRs as a useful process for reviewing code and ensuring standards are followed.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use CI tools to automate linting, coding practices, test runs, and other checks to streamline code reviews and maintain code quality. Do this with PR comments that become regular.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; include a summary of the changes, the motivation behind them, and any additional context that will help reviewers understand your work.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use a pull PR template to enforce the desired structure and information.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;markdown&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;# Description&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;What are you changing, and what does merging this achieve? Why is this change being made?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;# Screenshots&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Is this a UX change or can screenshots help the reviewer see the before and after or understand the solution better? Do you have any manual testing evidence?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;# Checklist&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [ ] Self-review complete&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [ ] Code builds without errors&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [ ] Relevant tests have been authored/updated&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [ ] All tests are passing locally&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk16&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [ ] Relevant documentation updates have been made&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; keep the scope of your PRs limited to make it easier for reviewers to understand and provide feedback.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; encourage discussions and feedback in PRs, and always be respectful and adhere to your team’s standards and practices.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create at minimum a CI pipeline for your PRS to ensure that code compiles, tests and linting succeed among other things.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; configure the PR to autocomplete with branch deletion.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; enforce due diligence on your PRs, for example, you can enforce that a PR should have tasks linked to it and have default individuals/groups assigned as reviewers.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use labels to categorize and organize pull requests.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create a process to ensure the review of PRs is done promptly to avoid blocking other team members’ progress. Not getting this right can be a common reason for a team to not commit to the process.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; encourage reviewers to provide specific examples or suggestions when requesting changes or improvements.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; encourage reviewers to be ready to pair with contributors to assist with recommendations they have provided.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; wire up your messaging system with your DevOps tool so notifications of PRs can be automatically pushed to the team.&lt;/p&gt;
&lt;h2&gt;Other&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; master your git tool and common git tasks.&lt;/p&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; allow credentials to leak in git. Leverage tools like Azure Vault and purge the history if credentials are accidentally committed. Also, assume the worst for credentials that leak to your repo and change them.&lt;/p&gt;
&lt;p&gt;🎃  DO resolve merge conflicts carefully, ensuring that the intended changes are preserved and the code remains functional. Communicate with your team members when resolving conflicts to avoid misunderstandings.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use rebasing to maintain a cleaner, linear commit history that makes it easier to track changes and debug issues by perusing through the history with or without visualisation and when using tools like &lt;code class=&quot;language-text&quot;&gt;git bisect&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Rebasing helps to integrate changes from one branch into another by replaying the commits of the feature branch onto the base branch. This creates a linear commit history, which can be easier to understand and navigate. In contrast, merging combines the two branches by creating a new merge commit, which may result in a more complex commit history.&lt;/p&gt;
&lt;p&gt;In the following example, we have a long-running branch, &lt;code class=&quot;language-text&quot;&gt;feature&lt;/code&gt;, that branches off &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt;. After our &lt;code class=&quot;language-text&quot;&gt;feature&lt;/code&gt; branch, we then have two additional commits from another branch &lt;code class=&quot;language-text&quot;&gt;bug&lt;/code&gt; that makes their way into the main first.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 422px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/1bcb60e1454ae3991de7a1f79a54b4a1/de25e/git-situation.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 69.90521327014217%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsSAAALEgHS3X78AAACpUlEQVR42o1TbUhTURh+3Ob8mNpybas1DEdKRUtq6A//rILlKAIlL7iiJA0LSvoREpYwCupP/cgkI5uRJEHXAolUFoqGykQu2KhWrW3XTeckN9Qk8Fene+6cyRLrhfd8vOd9n/Oc570X+IdZLFqNyWTIKynJyy8u1qnwP5advVig08VK5fLFgnhkSQMEdVlZZItC4dyr1181GgxNRq22LR9Y2AyEcv/4x9yyMrLNav2VtgqoUsU6iorml5XK6HO6Vyq/N0kk0es5ObPn1WqeBUgZ8LMi7tHKhMvlMQZYPF5f/9nR2Ni/bw1Hkm4w+DcJs2xion/78DB7hhAiGx9vrvnw6fBlMYMw0uSXEQIx5vejUvC85PMUOgwOviwfGOjc4fF4Cl2u22d9PGxri9cDnJzEiSRAkkKIKZWyIMQuSUR5PnOrfxK1dM2yfwMmYuEwbFNT0K8eeL2wOJ1YGB1FB91XV5vT6SV3nFrNuxBaZ0MoDwTBCEwqqfM8KoJBVAcCcIRCqPJ4YLNad9KmxMnMzEDd14djQ0PYT/d2e/ygWYg75nCaeJHmi0AzPQ2V15ulFp6a4XI1HOW4c6eEtYLjTKmUgCibnUCSAEi2dgHwyRxOJp4nNErU2e0e0/f2dtewLMlYS2AjEwvbf0DdubQCSNhVDSOR94pwmMtct7L5Cy7eGkOP4K/v+2CP32iWCaPkilOreBSRXHLMSw+1xdDweEZqbZ9H7cNZWGgeY98jFyYZdbOZ1ghM731F1Y1htN4cQUuLDxfERAbSeIJdYo8i59lCYXFXoPTug2XsfvHt4LWngV1HaF5dnSmVYcTvU7oyp/zzt6S6Dbx5a+vpdBvdnNvYy/ZXbVhAm8IIglPR6TpZR54fVI6Od4nd57hXB0ZGurM3AvwN7ykUUJ7WMi0AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;git-situation.png&quot;
        title=&quot;&quot;
        src=&quot;/static/1bcb60e1454ae3991de7a1f79a54b4a1/de25e/git-situation.png&quot;
        srcset=&quot;/static/1bcb60e1454ae3991de7a1f79a54b4a1/de25e/git-situation.png 422w&quot;
        sizes=&quot;(max-width: 422px) 100vw, 422px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;One way to sync the &lt;code class=&quot;language-text&quot;&gt;feature&lt;/code&gt; branch is to merge &lt;code class=&quot;language-text&quot;&gt;main&lt;/code&gt; into &lt;code class=&quot;language-text&quot;&gt;feature&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 472px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a17dd3a12393635cb2169d0051c3e3ec/85788/git-merge.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 62.5%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAANCAYAAACpUE5eAAAACXBIWXMAAAsSAAALEgHS3X78AAACsElEQVR42o1Ta0hTYRh+3NRKlpPaJINsXspbJDZay1xWP8w0E7NDF7D+SIgkRvT/UFYQiCSsy3SbZBJxUloUaEO2tcofOobgbHlLNzPb5WwVQkQ/Tuc720jDLi88vBe+9+H9nu/9gH+YUimRaTTSDLUaG/A/JpOFNLm5bL1U6t8VqXxWAr4s4HsRwOVIJOa81NQOdUpKXyGfpwNhRRQZtVVcAU25EvmmOJqmRcQjLY1tKSgIjyUnsw2ETqHwtAI/ylQqh1Eun2zk40M8DgNL5UCoMgK2AghUXbpmbmvV6WSkj6IoQixeMa3N1nfM7e4u5rjhzLHxk20cBzmp8z5utdt1BFFz0431QvLrDCcEDocjyWJ5vMflYhItFrfS7U49MzubtClCyK1KaPStO64P/EbociHdakWD04ndJG9vz15D/Mg0Tk/MoHJuDhmzs8jjkUswNZVQwNeK381gZ+8CmhutkJChSktL4/k2Eaansc9shmNoCIKGNL11LfFdi6BG5nHi0zzU773Y741A5fFsqZ6aSL8144Gmd1F0IUaoVCoTBEKKWSkkTYO8FjpZVOj8SFuuIX91senZi1Mm0+sckhuC4hpdCNK/6QyaixD2LOHog6UIYXQlMGl3yu2mwfwYgTGEaq2PTLhMw6uv0HxjGBe1HpSQvLwJgob3vOJygx9H7oRRpGex924IhdoQSgzfkKlnE3bc92O7MSy63BGCxhpsUjP2JmEj0PIGNp7QftuLRpKf10HQQmuVS9q/Iv/hQs4VYzDlXM/HrLruD5uvdwah6gzggMGHEn1QXKYL4OAge7a+392s+OPvia2J0za+beCRpfbLW27jc6a/zsFwEb2w+hpFNLMiXkBUu6gJDS+HGNUTa1fK6OjTjAFrdzapMRwlJmcJKA5CzDCUOPYoPwHOASKc9n1BiAAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;git-merge.png&quot;
        title=&quot;&quot;
        src=&quot;/static/a17dd3a12393635cb2169d0051c3e3ec/85788/git-merge.png&quot;
        srcset=&quot;/static/a17dd3a12393635cb2169d0051c3e3ec/85788/git-merge.png 472w&quot;
        sizes=&quot;(max-width: 472px) 100vw, 472px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This creates noise in the history as the fact that &lt;code class=&quot;language-text&quot;&gt;bug&lt;/code&gt; got merged first is not an important detail and we do not need to see the commit in &lt;code class=&quot;language-text&quot;&gt;feature&lt;/code&gt;. If the feature had been started after &lt;code class=&quot;language-text&quot;&gt;bug&lt;/code&gt; was merged would it have mattered? If the answer is no then you want to lean towards rebasing&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 422px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5cb24363d9ce883a945d713fe9bd3506/de25e/git-rebase.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 69.90521327014217%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAAAsSAAALEgHS3X78AAACiUlEQVR42pVTXUgUURg9O+6OZoxurKxkkDmwhYIusoGJxJQWCoJBNfSQslhiSJgv0UsLA5bUg5aRL5t/pSSyLImUpIluEvtjLKLhH9taauiGrsY+hL7d5s6sJoWlH5z5+A73O/fOud8Fdg8N/RQXZx7Kzjal5+XxR7Oykg9iL8FxEVNKSiSXZSMmlQkZgdUUjiMGjhszpaXdzuJ5W2Z8fOfh3FxivFZCuB2b7oQaBsPaC7P5x6ZeH+6itV6/YmOY8N2EhO83kpKCToAUsuzPi8BG0QUx2GB78LGUrrNarXEWi0VHkZGRwcpUTFSSxPH8XKKctR7P6yP9/R3lhBCdy1VfMT5eUE1XOCaVBrSHcaptFfkK59gW2D2Ghx1Xenraj83MzJzweh+WLyxApLzfD90+BImGEImRT6Xx++26LXZuzpi8vIwyVdCi8C9XIPxXcHoa5wcHse524zmtq6uLYgFBa7UKcbOzTNn8PC7JJ322FMDVkUXUNc3HFKgepm57SLHtYSgE49AQSlwunIzuwYiiGENBi4mJm5lj4zW3yBLi6QntIZylfKUdOkmSGLo+mjWQiFzI2M1TQhYP9PX1VDidH3hat4a1OS2rqqA0CZYQaGg/zXua0UAgEDs6OmjYqjsiyOncwBnVQ/FvDx/Pouq+B711Prxq+gIb5QQBWkEQFER9kS1Qx+bpNI43LzNVrWGca17DnbYl7emWddQ0BqE+isYASmvdaLnngf3JZygzZ6n8bfSfECBp6wmSur5ZLnd9Ndc2b7Lp3cG8hkefjDz2G0QeLyWvk8SB3oHr7g5iHH77rnDA4ctX/Y5eiijPE52pf12O2qAKTk29SX3vdSq/6PN1m3d6+QucQwIMLiK3QQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;git-rebase.png&quot;
        title=&quot;&quot;
        src=&quot;/static/5cb24363d9ce883a945d713fe9bd3506/de25e/git-rebase.png&quot;
        srcset=&quot;/static/5cb24363d9ce883a945d713fe9bd3506/de25e/git-rebase.png 422w&quot;
        sizes=&quot;(max-width: 422px) 100vw, 422px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Notice how the history now looks cleaner.&lt;/p&gt;
&lt;p&gt;🎃 &lt;strong&gt;DO BE AWARE&lt;/strong&gt; that while rebasing is great and encouraged,  the potential risks and complications when rebasing shared branches can be quite compromising.&lt;/p&gt;
&lt;p&gt;Recommended workflow (simplified)&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 615px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2ab184a64ac98522cd846f2a70ae368c/8ab79/workflow.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 126.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAZCAYAAAAxFw7TAAAACXBIWXMAAAsSAAALEgHS3X78AAAD7klEQVR42p1VbWhbVRhuu6zd2mE7FFFBAqH4Q2irhNaJsIhpqz+GglBEFPdL6g9hLOIYDG3nqg5cFfzlEEEYzNlBW4VFm3a5DWmT3uTee+7HuR+5N1+3vUnukmbJtnbDDbyekzQjatd1eeHwvufjPve853nOe5qa6syyrD3Y86AwylD6ugRNlQPZIs/kXXh8aqo6v2tDgM3Yp6WNp1Opuy/7/Zw7Hr/9SiJhddbPP7JpsNxtpP56cXY2cDgul52acPvZrV/uHpAgCBuEViuOoZC/wHPZTZ7LGIBZ3RSF4jge93rVttqxNGQ9PT0HkXv0NFX17zYQzZwQhfxZCRYmeDZzRhYKp4MBcVIAuS8gmzsj8YUJDmTOQS7/4UMBMxmrHQFdUpX1QCxWXBChSchyYZFh9CWOMxZF8ZpfkQvzIsyFZbH4XZWgBnZut3d2NZRyVWNTe9CB763q0BxFhAgRMknyrAFFvjxYIQvCVrzuoUBzc2wHWnxgZobAO+qY84JhyJufCVzuU9TGZy+HX0Lj7V6vF7Pcgpnept3PpJkkQ0f9ft9XCwu+Y1s72CnNnY9AEcvvaLHSeJSMfyPB3ISqXH+/wrxQHtZi5VMxufiJppQ8yfitYziOhOKfq0rpuCIVPZpyw1P1JQ+EG09VAEUu/wND64womIuAyTAsyF6sjhdPIFFLLFgLcaxBojjKMmvRCJmgUT8KaD0i8NkVmkqTHGOQkLn5fCPcNdvt9q6GPqwrGC3Yc8D8WuCNAMuu+kTRvKrJt16tkborablcLhtq+wYHB3GlOTB3JXqapvQfOWB8D5i1n7wzpLtW8rYYfiBos9Pp7Ozr6+vq7e3twKDIPzkyMlLRn8PhqJSy6enp55aWgmcDAeJcMBgcqs/mXzYwMPAYBqr1MThqFcFTFLXX4XR0ynThGUlY/2AlGPvYP097AL02CkHphZ0qTMt2/fPnKQy8X+SuH5aEfE6WChpSRwwK19ZV6ebJbQFxqvWA3d3dbf39/Y+jXbZvpY1rZu36tdTFTbsCxAc+Nja2D4W2wEJsgKWNaSqauITenAsrIfU3PX7Xue354Q8xY0eOvPsETo0gLBuu4rjsW2PVxd7fIy4ylLgi8LmfQ0vKZVQff1GlzUPVwmG1PugRa6+RMDk5uZ8grh4Ph8Pf+nx/fPQfjdrqM/nfS8fz5YPp9B23AotvRCLJN1H82vyf1HtkSDq6vLxsF7m028xYQ8nkxutm5t5QOBx/GxXgt4z0PTdeqyfvDOvxTef93CXqxiEk3BR6nDRAr6osWFUBo2eRPH7F8yzIfYnutSmwWQUxq1HRlMayhoZEjlsM3XNDYAsX/wGJq5BPpeFLsgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;worflow&quot;
        title=&quot;&quot;
        src=&quot;/static/2ab184a64ac98522cd846f2a70ae368c/8ab79/workflow.png&quot;
        srcset=&quot;/static/2ab184a64ac98522cd846f2a70ae368c/0eb09/workflow.png 500w,
/static/2ab184a64ac98522cd846f2a70ae368c/8ab79/workflow.png 615w&quot;
        sizes=&quot;(max-width: 615px) 100vw, 615px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Handling Large PRs&lt;/h3&gt;
&lt;p&gt;In instances where you’re dealing with large pull requests, it’s beneficial to break them into smaller, more manageable parts. This approach makes reviewing easier and faster, as each part can focus on a specific feature or issue. When breaking down a PR, aim to ensure that each smaller PR is self-contained and does not introduce incomplete features or dependencies on other PRs. This strategy not only streamlines the review process but also minimizes the risk of introducing bugs due to complex changes being overlooked in a massive PR.&lt;/p&gt;
&lt;p&gt;While it’s generally best to avoid large pull requests (PRs) as they can complicate the review process and increase the risk of bugs, there are scenarios where they might be acceptable. For example, changes that are widespread but superficial, such as updates to a package.json file or mass-renaming operations, can be handled in a single large PR. However, for most development work, large PRs should be discouraged due to their complexity and the challenges they present in thorough reviewing and understanding the impact of changes.&lt;/p&gt;
&lt;p&gt;One effective strategy for managing large changes is through granular commits. Even if a PR is sizeable, having well-structured, logical commits within it can significantly ease the review process. Each commit should represent a single, coherent change, making it easier for reviewers to understand and track changes step by step. This approach not only facilitates easier code reviews but also aids in future troubleshooting, as each commit stands as a clear record of a specific change.&lt;/p&gt;
&lt;p&gt;In cases where large PRs are unavoidable, ensure that they are well-documented, with a clear description of each change and its purpose. Encourage reviewers to focus on individual commits rather than the entire PR at once, to better manage the review process. This granular approach to both commits and PR reviews can help maintain the quality and integrity of the codebase, even when dealing with substantial changes.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;In conclusion, effective Git management is pivotal for a disciplined and efficient development workflow. By adhering to best practices for commits, branch management, and pull requests, teams can maintain a clean and understandable Git history, facilitate easier code reviews, and ensure secure and streamlined collaboration. Large pull requests should be approached with caution, broken down into smaller parts when possible. Real-world experiences teach us the value of these practices in maintaining project health and team productivity. Embracing these guidelines will not only enhance your individual skill set but also contribute significantly to the success of your team’s collaborative efforts in software development.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtkb { font-weight: bold; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk16 { color: #6796E6; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Dotnet must know - Serializable Exceptions]]></title><description><![CDATA[Photo by UX Indonesia on Unsplash Ensuring Custom Exceptions are Serializable and Implement the Four Core Constructors This article is part…]]></description><link>http://www.drunkonmonads.com/dotnet-musts-exceptions-serializable/</link><guid isPermaLink="false">http://www.drunkonmonads.com/dotnet-musts-exceptions-serializable/</guid><pubDate>Fri, 17 Mar 2023 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@uxindo?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;UX Indonesia&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/WCID2JWoxwE?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Ensuring Custom Exceptions are Serializable and Implement the Four Core Constructors&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;This article is part of a series for &lt;a href=&quot;https://www.drunkonmonads.com/tags/dotnet-must-know/&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Dotnet must know&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Exceptions are an integral part of any software application, and custom exceptions provide a way to handle application-specific errors in a more specific and meaningful way. However, when creating custom exceptions, it’s important to ensure they are serializable and implement the four core constructors.&lt;/p&gt;
&lt;h2&gt;Why Is This Important?&lt;/h2&gt;
&lt;p&gt;When an exception occurs in an application, it may need to be propagated across different tiers or processes or even persisted to a log or database. In such cases, the exception object must be serializable so that it can be transmitted or stored. If the exception object is not serializable, it may not be possible to propagate or store it, resulting in the loss of valuable debugging information.&lt;/p&gt;
&lt;p&gt;In modern .NET architectures like distributed systems and microservices, the ability to serialize exceptions becomes increasingly significant. In these environments, exceptions often need to travel across different service boundaries or machine boundaries. For instance, when an exception occurs in a microservice, it might need to be serialized to be sent to a logging service or to be propagated to another service for handling. Without proper serialization, these distributed components would lose the ability to communicate detailed error information effectively, leading to challenges in diagnosing and resolving issues in a distributed architecture.&lt;/p&gt;
&lt;p&gt;The four core constructors provide a way to initialize an exception object with the necessary information. The parameterless constructor initializes the exception object with default values, while the constructor that takes a string message initializes it with a user-defined message. The constructor that takes a string message and an inner exception initializes it with a user-defined message and the inner exception that caused the current exception. Finally, the constructor that takes a SerializationInfo object and a StreamingContext object is used to initialize an exception object during deserialization.&lt;/p&gt;
&lt;p&gt;Enforcing this rule ensures consistency as the expectations will always be the same for all custom Exceptions.&lt;/p&gt;
&lt;h2&gt;Enforcing This Using Unit Tests&lt;/h2&gt;
&lt;p&gt;To ensure that all custom exceptions in an application are serializable and implement the four core constructors, we can use unit tests. Here’s an example of how to do this in xUnit and Fluent Assertions:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;/// At a minimum, you should mark your custom exception as serializable and implement the four basic constructors&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ExceptionSerializationTests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Fact&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GivenAnAssemblyContainingExceptionTypes_ShouldEnsureAllExceptionTypesAreSerializable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assembly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AssemblyMarker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Assembly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assembly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ContainSerializableExceptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Fact&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GivenAnAssemblyContainingExceptionTypes_ShouldEnsureAllExceptionTypesHaveTheFourBasicConstructors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assembly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AssemblyMarker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Assembly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assembly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ContainExceptionsImplementingAllBaseConstructors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This test checks all custom exceptions in the given assembly to ensure they are marked with the Serializable attribute. It’s crucial because it allows these exceptions to be serialized and deserialized, a necessary feature for error handling across different application domains or services.&lt;/p&gt;
&lt;p&gt;This test ensures that each custom exception type has the four essential constructors. These constructors provide flexibility in initializing exceptions with different levels of detail - from a simple message to wrapping another exception as an inner exception.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;/// Extension methods for Fluent Assertions to provide custom assertions for the Assembly type.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AssemblyAssertionsExtensions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// Asserts that all custom exception types in the assembly are decorated with the Serializable attribute.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;assertions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;The assembly assertions.&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;A chainable assertion object.&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AndConstraint&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AssemblyAssertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ContainSerializableExceptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AssemblyAssertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionTypes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Subject&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetTypes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;IsSubclassOf&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)) &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;IsAbstract&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionTypes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Assertion&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ForCondition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Attribute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;IsDefined&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SerializableAttribute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FailWith&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$&amp;quot;Expected exception type &amp;#39;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionType&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;}&amp;#39; to be decorated with SerializableAttribute.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AndConstraint&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AssemblyAssertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// Asserts that all custom exception types in the assembly have the four basic constructors: parameterless,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// string message, string message and inner exception, and SerializationInfo and StreamingContext.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;assertions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;The assembly assertions.&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;A chainable assertion object.&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AndConstraint&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AssemblyAssertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ContainExceptionsImplementingAllBaseConstructors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AssemblyAssertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionTypes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Subject&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetTypes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;IsAssignableFrom&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;t&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionTypes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;constructors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetConstructors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;BindingFlags&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;NonPublic&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;BindingFlags&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Instance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;BindingFlags&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Assertion&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ForCondition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;constructors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetParameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FailWith&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$&amp;quot;Expected exception type &amp;#39;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionType&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;}&amp;#39; to have a parameterless constructor.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Assertion&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ForCondition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;constructors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetParameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetParameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ParameterType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FailWith&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$&amp;quot;Expected exception type &amp;#39;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionType&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;}&amp;#39; to have a constructor that takes a string message.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Assertion&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ForCondition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;constructors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetParameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetParameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ParameterType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetParameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ParameterType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FailWith&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$&amp;quot;Expected exception type &amp;#39;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionType&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;}&amp;#39; to have a constructor that takes a string message and an inner exception.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Assertion&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ForCondition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;constructors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;IsFamily&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetParameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetParameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ParameterType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Runtime&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Serialization&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SerializationInfo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &amp;amp;&amp;amp;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetParameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()[&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ParameterType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Runtime&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Serialization&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;StreamingContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FailWith&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$&amp;quot;Expected exception type &amp;#39;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exceptionType&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;}&amp;#39; to have a protected constructor that takes a SerializationInfo object and a StreamingContext object.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AndConstraint&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AssemblyAssertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;assertions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By enforcing these requirements using unit tests, we can ensure that all custom exception types in our application are serializable and can be properly initialized with the necessary information. This helps us avoid potential bugs and loss of valuable debugging information in the event of an exception.&lt;/p&gt;
&lt;h2&gt;Best Practices in Designing Custom Exceptions&lt;/h2&gt;
&lt;p&gt;While ensuring exceptions are serializable and implementing the core constructors are foundational, there are additional best practices to consider for robust custom exception design:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Meaningful Properties: Include properties that carry relevant information about the error condition. For example, if you have a FileReadException, consider adding properties like &lt;code class=&quot;language-text&quot;&gt;FileName&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;FileLocation&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Exception Hierarchies: Establish a clear hierarchy of exceptions, especially in larger applications. This helps in categorizing and handling exceptions at different levels.&lt;/li&gt;
&lt;li&gt;Avoid Excessive Details: While detailed exceptions are helpful, avoid including sensitive information like database credentials or encryption keys in the exception details.&lt;/li&gt;
&lt;li&gt;Documentation: Clearly document each custom exception, specifying when and how it should be used. This clarity is vital for anyone else using or maintaining your code.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By adhering to these practices, you not only enhance the functionality of your custom exceptions but also improve the maintainability and clarity of your error handling logic.”&lt;/p&gt;
&lt;p&gt;Incorporating these enhancements will provide a more comprehensive understanding for readers, making the blog not only a guide but also a best practices reference in the realm of .NET exception handling.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk17 { color: #808080; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Must know Roslyn rules - Cancellation Tokens]]></title><description><![CDATA[Photo by Tingey Injury Law Firm on Unsplash Must know Roslyn rules - Cancellation Tokens This article is part of a series for  CA106…]]></description><link>http://www.drunkonmonads.com/roslyn-analyzers-cancellation-tokens/</link><guid isPermaLink="false">http://www.drunkonmonads.com/roslyn-analyzers-cancellation-tokens/</guid><pubDate>Fri, 17 Mar 2023 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/pt-br/@tingeyinjurylawfirm?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Tingey Injury Law Firm&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/veNb0DDegzE?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Must know Roslyn rules - Cancellation Tokens&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;This article is part of a series for &lt;a href=&quot;https://www.drunkonmonads.com/tags/roslyn-rules/&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Must know Roslyn rules&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;CA1068: &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1068&quot;&gt;CancellationToken parameters must come last&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;This rule suggests that &lt;code class=&quot;language-text&quot;&gt;CancellationToken&lt;/code&gt; parameters should be placed at the end of the parameter list. This is because CancellationToken is a special type of parameter that is used to signal cancellation of a long-running operation. By convention, it is placed at the end of the parameter list to make it clear that it is an optional parameter. We can configure the rule as follows in an &lt;code class=&quot;language-text&quot;&gt;.editorconfig&lt;/code&gt; file.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;swift&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CA1068&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;severity&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CA1068&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exclude&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = *_generated.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cs&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we’ve set the rule to error, which fails the build on violation. We’ve also excluded generated files from this rule using the exclude property.&lt;/p&gt;
&lt;h1&gt;CA2016: &lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2016&quot;&gt;Forward the CancellationToken parameter to methods that take one&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;CA2016 is a code analysis rule in Roslyn that checks whether a method that performs a long-running operation takes a CancellationToken parameter, and if it does, whether it forwards that parameter to any other methods that also take a CancellationToken parameter.&lt;/p&gt;
&lt;p&gt;This rule suggests that methods that take a CancellationToken parameter should forward that parameter to any other methods that also take a CancellationToken parameter. This can help ensure that a long-running operation can be cancelled gracefully if needed.&lt;/p&gt;
&lt;p&gt;Let’s look at an example. Consider the following method:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;DoLongRunningOperationAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Do something that takes a long time&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Delay&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Return a value&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This method takes a CancellationToken parameter but does not forward it to any other methods. If we run the code analysis tool in Visual Studio, we’ll get a warning that suggests we should forward the CancellationToken parameter to any other methods that also. We can fix the violation.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;DoLongRunningOperationAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Do something that takes a long time, and pass the CancellationToken parameter to Task.Delay&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Delay&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Return a value&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this updated implementation, the &lt;code class=&quot;language-text&quot;&gt;cancellationToken&lt;/code&gt; parameter is passed to the &lt;code class=&quot;language-text&quot;&gt;Task.Delay&lt;/code&gt; method, which also takes a &lt;code class=&quot;language-text&quot;&gt;CancellationToken&lt;/code&gt; parameter. This ensures that the long-running operation can be cancelled gracefully if needed.&lt;/p&gt;
&lt;p&gt;To configure the CA2016 rule in an .editorconfig file, we can use the following settings:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;swift&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CA2016&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;severity&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CA2016&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exclude&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = *_generated.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cs&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;While the CA1068 and CA2016 rules are independent of each other and can be configured separately, there is value in configuring them together to ensure that all method signatures are consistent and readable.&lt;/p&gt;
&lt;p&gt;The CA1068 rule has exceptions for methods with optional parameters or ref/out parameters following a CancellationToken parameter. While these exceptions make sense for those specific scenarios, it’s still a good idea to keep method signatures consistent and easy to read. For example, even if a method has optional parameters following a CancellationToken parameter, we might still want to keep the CancellationToken parameter at the end of the parameter list to make it clear that it is optional and to maintain consistency with other methods that have a CancellationToken parameter&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Consuming SOAP Services with the HttpClient]]></title><description><![CDATA[Photo by Aurélia Dubois on Unsplash Consuming Legacy SOAP Services with the HttpClient in .NET In this article, we will discuss how to…]]></description><link>http://www.drunkonmonads.com/SOAP with HttpClient/</link><guid isPermaLink="false">http://www.drunkonmonads.com/SOAP with HttpClient/</guid><pubDate>Thu, 09 Mar 2023 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@aureliaduboisphotographie?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Aurélia Dubois&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/6J0MUsmS4fQ?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Consuming Legacy SOAP Services with the HttpClient in .NET&lt;/h1&gt;
&lt;p&gt;In this article, we will discuss how to consume legacy SOAP services using the HttpClient in .NET. The HttpClient class is used to send HTTP requests to a web server and receive its responses. We will see how to use it to send SOAP requests to a SOAP service and process its responses.&lt;/p&gt;
&lt;h1&gt;Introduction to SOAP Services&lt;/h1&gt;
&lt;p&gt;SOAP (Simple Object Access Protocol) is a messaging protocol used to exchange structured data between applications. It relies on XML to provide a common message format that can be understood by different systems, regardless of their programming languages and platforms.&lt;/p&gt;
&lt;p&gt;In recent years, SOAP has been superseded by more modern protocols such as REST and gRPC. However, there are still many legacy SOAP services that are widely used and need to be integrated into modern applications.&lt;/p&gt;
&lt;p&gt;In this blog post, I will show you how to consume a legacy SOAP service using the HttpClient in .NET. We will use a SOAP service that converts a given number to words as an example.&lt;/p&gt;
&lt;h1&gt;Overview of our example&lt;/h1&gt;
&lt;p&gt;Our SOAP service, called NumberToWords, takes an integer as input and returns its English representation in words. For example, if the input is 500, the service will return “five hundred”.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.dataaccess.com/webservicesserver/NumberConversion.wso&quot;&gt;NumberConversion&lt;/a&gt; has a service, &lt;a href=&quot;https://www.dataaccess.com/webservicesserver/NumberConversion.wso?op=NumberToWords&quot;&gt;NumberToWords&lt;/a&gt;, which returns the word corresponding to the positive number passed as parameter limited to quadrillions. Due to its simplicity we will use it in this example&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;To call this service, we need to send an XML request message in the SOAP format to the service endpoint. The service will then return an XML response message in the SOAP format containing the result.&lt;/p&gt;
&lt;p&gt;Here is an example input:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; encoding&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Envelope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns:soap&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://schemas.xmlsoap.org/soap/envelope/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Body&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;NumberToWords&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://www.dataaccess.com/webservicesserver/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ubiNum&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ubiNum&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;NumberToWords&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Body&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Envelope&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and matching output:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; encoding&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Envelope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns:soap&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://schemas.xmlsoap.org/soap/envelope/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Body&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;m:NumberToWordsResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns:m&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://www.dataaccess.com/webservicesserver/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;m:NumberToWordsResult&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;five hundred &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;m:NumberToWordsResult&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;m:NumberToWordsResponse&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Body&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Envelope&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Consuming SOAP Services with HttpClient&lt;/h1&gt;
&lt;p&gt;To consume a SOAP service with the &lt;code class=&quot;language-text&quot;&gt;HttpClient&lt;/code&gt;, we need to create an XML request message that follows the SOAP protocol and send it to the SOAP service using an HTTP POST request. The response message is also an XML message that follows the SOAP protocol.&lt;/p&gt;
&lt;p&gt;To create the SOAP request message, we need to create an XML document that follows the SOAP protocol and contains the SOAP envelope, header, and body. The body of the SOAP message contains the actual request data that is sent to the service.&lt;/p&gt;
&lt;p&gt;We can use the &lt;code class=&quot;language-text&quot;&gt;HttpClient&lt;/code&gt; class to send the SOAP request message to the service using an HTTP POST request. To process the response message, we need to deserialize the XML response message into a .NET object. We can use the XmlSerializer class to deserialize the XML message into a .NET object&lt;/p&gt;
&lt;h1&gt;Sample implementation&lt;/h1&gt;
&lt;p&gt;The code provided in this blog post is written in C#. Let us start by looking at the classes involved in consuming the NumberToWords service.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberToWordsRequestBody&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;XmlElement&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Namespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;NumberConversionNamespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ElementName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;NumberToWords&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberToWordsRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberToWordsRequest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;XmlElement&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ElementName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;ubiNum&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberToWordsResponseBody&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;XmlElement&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ElementName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;NumberToWordsResponse&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Namespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;NumberConversionNamespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberToWordsResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberToWordsResponse&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;XmlElement&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ElementName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;NumberToWordsResult&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;XmlType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Namespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;EnvelopeNamespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TypeName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Envelope&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Envelope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;NumberToWordsRequestBody&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;NumberToWordsRequest&lt;/code&gt; classes represent the input message. The &lt;code class=&quot;language-text&quot;&gt;NumberToWordsResponseBody&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;NumberToWordsResponse&lt;/code&gt; classes represent the output message. The &lt;code class=&quot;language-text&quot;&gt;Envelope&amp;lt;T&gt;&lt;/code&gt; class is a generic class used to wrap the input and output messages.&lt;/p&gt;
&lt;p&gt;Next, let us look at a sample client, &lt;code class=&quot;language-text&quot;&gt;NumberConversionClient&lt;/code&gt;, which is responsible for making the HTTP request to the NumberToWords service.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BaseClient&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ApiPath&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;NumberConversion.wso&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NumberConversionClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IHttpClientFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpClientFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ILogger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        : &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpClientFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ConvertNumberToWords&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Envelope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberToWordsRequestBody&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberToWordsRequestBody&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberToWordsRequest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;number&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Envelope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberToWordsRequestBody&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Envelope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberToWordsResponseBody&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ApiPath&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BaseClient&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ILogger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;HttpClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BaseClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IHttpClientFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;clientFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ILogger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;HttpClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;clientFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CreateClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;BaseClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ?? &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ArgumentNullException&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;DeserializeResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetApiResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;HttpMethod&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Post&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;virtual&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpResponseMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetApiResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpMethod&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BeginScope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;path&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpRequestMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; != &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;StringContent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Serialize&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(), &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;UTF8&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Format&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;HttpClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SendAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;virtual&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;DeserializeResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpResponseMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;StatusCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BeginScope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;responseType&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FullName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;IsSuccessStatusCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;try&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;HttpUtility&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;HtmlDecode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ReadAsStringAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Deserialize&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Exception&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exception&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;deserializeFailureMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Could not deserialize the response input stream&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;LogError&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;deserializeFailureMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DomainException&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$&amp;quot;{&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;deserializeFailureMessage&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;} {&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeof&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TResponse&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FullName&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exception&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ReadAsStringAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;LogError&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;SOAP responses should always return OK status code with details. Received {statusCode} {content}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;statusCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DomainException&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;SOAP responses should always return OK status code with details&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code relies on some extensions. &lt;code class=&quot;language-text&quot;&gt;SoapExtensions&lt;/code&gt; is a static class that contains extension methods to help with the serialization and deserialization of SOAP requests and responses. It consists of the following methods:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;ToXDocument&lt;/code&gt;: This method takes an object of type &lt;code class=&quot;language-text&quot;&gt;T&lt;/code&gt; and returns an instance of &lt;code class=&quot;language-text&quot;&gt;XDocument&lt;/code&gt;. The method first creates a new instance of &lt;code class=&quot;language-text&quot;&gt;XDocument&lt;/code&gt; with the necessary XML declaration and then uses an &lt;code class=&quot;language-text&quot;&gt;XmlSerializer&lt;/code&gt; to serialize the input object into an XML document. If any errors occur during serialization, a &lt;code class=&quot;language-text&quot;&gt;DomainException&lt;/code&gt; is thrown.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Serialize&lt;/code&gt;: This method takes an object of type &lt;code class=&quot;language-text&quot;&gt;T&lt;/code&gt; and returns a string representing the serialized XML document. It simply calls the &lt;code class=&quot;language-text&quot;&gt;ToXDocument&lt;/code&gt; method and returns the resulting &lt;code class=&quot;language-text&quot;&gt;XDocument&lt;/code&gt; as a string.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;language-text&quot;&gt;Deserialize&lt;/code&gt;: This method takes a string representing an XML document and deserializes it into an object of type &lt;code class=&quot;language-text&quot;&gt;T&lt;/code&gt;. The method first creates an &lt;code class=&quot;language-text&quot;&gt;XmlSerializer&lt;/code&gt; instance and then uses it to deserialize the input XML string into an object of type &lt;code class=&quot;language-text&quot;&gt;T&lt;/code&gt;. If any errors occur during deserialization, a &lt;code class=&quot;language-text&quot;&gt;DomainException&lt;/code&gt; is thrown.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By defining these extension methods, we can easily serialize and deserialize SOAP requests and responses using simple method calls.&lt;/p&gt;
&lt;p&gt;For completeness here are the constants referenced in the other code snippets.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Constants&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TextXmlContentType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;text/xml; charset=utf-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Format&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;text/xml&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;EnvelopeNamespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://schemas.xmlsoap.org/soap/envelope/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Standalone&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Encoding&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;NumberConversionNamespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://www.dataaccess.com/webservicesserver/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Testing our sample&lt;/h1&gt;
&lt;p&gt;Let’s write an integration test for the client that we have just created. First, let’s introduce some configuration options.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;NumberConversion&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Uri&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;BaseAddress&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TimeSpan&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;RequestTimeOut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptionsValidator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AbstractValidator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NumberConversionOptionsValidator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RuleFor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;BaseAddress&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Must&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;IsAbsoluteUri&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Scheme&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Uri&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;UriSchemeHttps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptionsValidatorExtensions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ValidateAndThrow&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptionsValidator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ValidateAndThrow&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;NumberConversionOptions&lt;/code&gt; class defines the configuration options for the SOAP service. It has two properties, &lt;code class=&quot;language-text&quot;&gt;BaseAddress&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;RequestTimeOut&lt;/code&gt;. The &lt;code class=&quot;language-text&quot;&gt;BaseAddress&lt;/code&gt; property is the base URI for the service, while the &lt;code class=&quot;language-text&quot;&gt;RequestTimeOut&lt;/code&gt; property specifies the timeout for the HTTP request.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;NumberConversionOptionsValidator&lt;/code&gt; class is used to validate the configuration options specified in the &lt;code class=&quot;language-text&quot;&gt;NumberConversionOptions&lt;/code&gt; class. It uses the &lt;code class=&quot;language-text&quot;&gt;FluentValidation&lt;/code&gt; library to ensure that the BaseAddress property is an absolute HTTPS URI.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;NumberConversionOptionsValidatorExtensions&lt;/code&gt; class provides an extension method that allows us to easily validate an instance of the &lt;code class=&quot;language-text&quot;&gt;NumberConversionOptions&lt;/code&gt; class using the &lt;code class=&quot;language-text&quot;&gt;ValidateAndThrow&lt;/code&gt; method. If the options are invalid, an exception is thrown.&lt;/p&gt;
&lt;p&gt;Our configuration can look as follows in JSON:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;NumberConversion&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;BaseAddress&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;https://www.dataaccess.com/webservicesserver/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;RequestTimeOut&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;00:01:00&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next, let us add an extension for bootstrapping the client into a service collection.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionExtensions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IServiceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddHttpClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IServiceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IConfigurationSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ArgumentNullException&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Configure&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;config&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ValidateAndThrow&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddHttpClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;BaseClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;BaseAddress&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;!.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;BaseAddress&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Timeout&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;RequestTimeOut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;client&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DefaultRequestHeaders&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Accept&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Constants&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TextXmlContentType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddTransient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;NumberConversionExtensions&lt;/code&gt; class provides an extension method to bootstrap the &lt;code class=&quot;language-text&quot;&gt;NumberConversionClient&lt;/code&gt;. The &lt;code class=&quot;language-text&quot;&gt;AddHttpClient&lt;/code&gt; method takes an &lt;code class=&quot;language-text&quot;&gt;IServiceCollection&lt;/code&gt; and an &lt;code class=&quot;language-text&quot;&gt;IConfigurationSection&lt;/code&gt; as parameters. It configures an instance of &lt;code class=&quot;language-text&quot;&gt;NumberConversionOptions&lt;/code&gt; and registers it with the service collection.&lt;/p&gt;
&lt;p&gt;Next, the method validates and throws an exception on invalid options, using the validator we created earlier with &lt;code class=&quot;language-text&quot;&gt;FluentValidation&lt;/code&gt;. Then it creates and configures an instance of &lt;code class=&quot;language-text&quot;&gt;HttpClient&lt;/code&gt; with the base address and timeout values provided in &lt;code class=&quot;language-text&quot;&gt;NumberConversionOptions&lt;/code&gt;. Finally, it registers an instance of &lt;code class=&quot;language-text&quot;&gt;NumberConversionClient&lt;/code&gt; with the service collection, which allows it to be used in the application.&lt;/p&gt;
&lt;p&gt;Before we can write integration tests, we need to create a fixture. A fixture is a reusable object that contains test data, configuration settings, and any other objects required by the tests. Fixtures can help reduce code duplication and make tests easier to read and maintain.&lt;/p&gt;
&lt;p&gt;In our case, we’ll create a fixture that sets up the &lt;code class=&quot;language-text&quot;&gt;HttpClient&lt;/code&gt; and other required dependencies, such as the &lt;code class=&quot;language-text&quot;&gt;NumberConversionOptions&lt;/code&gt;. We’ll use the &lt;code class=&quot;language-text&quot;&gt;AutoMocker&lt;/code&gt; library to help us create and inject these dependencies.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CollectionDefinition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;NumberConversionCollectionFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionCollectionFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ICollectionFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IAsyncLifetime&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;InitializeAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetConfigurationSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpClientFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CreateHttpClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AutoMocker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AutoMocker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AutoMocker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Use&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;httpClientFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AutoMocker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Use&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AutoMocker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Use&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CompletedTask&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IConfigurationSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetConfigurationSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TestConfigurationExtensions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;NumberConversionOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;DisposeAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CompletedTask&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AutoMocker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AutoMocker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IHttpClientFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;) &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CreateHttpClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IConfigurationSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;serviceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ServiceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;serviceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddHttpClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;serviceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BuildServiceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IHttpClientFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;provider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code block defines two classes that are used to initialize and dispose of the dependencies required for testing &lt;code class=&quot;language-text&quot;&gt;NumberConversionClient&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;NumberConversionCollectionFixture&lt;/code&gt; is a collection fixture that provides the context for the tests. This fixture is used to set up the &lt;code class=&quot;language-text&quot;&gt;HttpClient&lt;/code&gt; and the dependencies for &lt;code class=&quot;language-text&quot;&gt;NumberConversionClient&lt;/code&gt;. The &lt;code class=&quot;language-text&quot;&gt;NumberConversionFixture&lt;/code&gt; implements &lt;code class=&quot;language-text&quot;&gt;IAsyncLifetime&lt;/code&gt;, which provides the methods for setting up and tearing down the dependencies.&lt;/p&gt;
&lt;p&gt;To ensure that our SOAP service client works as expected, we need to write integration tests that will verify the client’s behaviour. For this, we’ll use xUnit.net as our test framework.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;10&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Collection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;NumberConversionCollectionFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Trait&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;TestCategory&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TestCategories&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Integration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionClientTests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_fixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NumberConversionClientTests&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_fixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Fact&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GivenValidInput_ThenConvertNumberToWords_ShouldReturnInWords&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_fixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AutoMocker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CreateInstance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NumberConversionClient&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ConvertNumberToWords&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;five hundred &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NotBeNullOrEmpty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;First, we created a test class called &lt;code class=&quot;language-text&quot;&gt;NumberConversionClientTests&lt;/code&gt; and marked it with the &lt;code class=&quot;language-text&quot;&gt;[Collection]&lt;/code&gt; attribute. This attribute is used to indicate that the tests in this class require a shared resource, in our case the &lt;code class=&quot;language-text&quot;&gt;NumberConversionFixture&lt;/code&gt;. This fixture will set up the required infrastructure to create an instance of the &lt;code class=&quot;language-text&quot;&gt;NumberConversionClient&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;Next, we added a test method called &lt;code class=&quot;language-text&quot;&gt;GivenValidInput_ThenConvertNumberToWords_ShouldReturnInWords&lt;/code&gt; that will test our SOAP client’s ability to convert a number to words. In this method, we’ll create an instance of the &lt;code class=&quot;language-text&quot;&gt;NumberConversionClient&lt;/code&gt; class using the &lt;code class=&quot;language-text&quot;&gt;AutoMocker&lt;/code&gt; instance provided by the fixture. We’ll then call the &lt;code class=&quot;language-text&quot;&gt;ConvertNumberToWords&lt;/code&gt; method with a valid input value of &lt;code class=&quot;language-text&quot;&gt;500&lt;/code&gt; and verify that the result is &lt;code class=&quot;language-text&quot;&gt;five hundred&lt;/code&gt; using the &lt;code class=&quot;language-text&quot;&gt;FluentAssertions&lt;/code&gt; library.&lt;/p&gt;
&lt;p&gt;Running this integration test will ensure that our SOAP service client is working as expected and can be used in our application with confidence.&lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;In this article, we discussed how to consume legacy SOAP services using the &lt;code class=&quot;language-text&quot;&gt;HttpClient&lt;/code&gt; in .NET. We saw how to create the SOAP request message and send it to the &lt;code class=&quot;language-text&quot;&gt;SOAP&lt;/code&gt; service using an HTTP POST request. We also saw how to deserialize the XML response message into a .NET object.&lt;/p&gt;
&lt;p&gt;By using the &lt;code class=&quot;language-text&quot;&gt;HttpClient&lt;/code&gt; class, we could easily integrate with SOAP services in .NET and process their responses. While SOAP services are being phased out in favour of RESTful services, there are still many legacy systems that use SOAP services, and it is important to know how to integrate with them using modern tools and technologies.&lt;/p&gt;
&lt;h1&gt;Bonus Section - Working with CData&lt;/h1&gt;
&lt;p&gt;CDATA (short for Character Data) is a way to include unescaped character data, including markup characters such as &lt;code class=&quot;language-text&quot;&gt;&amp;lt;&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;&gt;&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;&amp;amp;&lt;/code&gt;, within an XML document. CDATA sections begin with the string &lt;code class=&quot;language-text&quot;&gt;&amp;lt;![CDATA[ and end with ]]&gt;&lt;/code&gt;. Within a CDATA section, characters are not parsed as markup, but are instead treated as normal character data.&lt;/p&gt;
&lt;p&gt;Using CDATA sections can be useful when including text that contains reserved characters or markup that should be preserved as-is, without being parsed as XML. In the context of SOAP web services, CDATA can be used to include XML fragments in messages without causing parsing errors or losing information.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;11&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    public class SampleObject&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;        [XmlElement(ElementName = &amp;quot;CDataSection&amp;quot;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;        public XmlCDataSection Transaction&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;            get&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;                var xDocument = SampleNestedObjectInternal.ToXDocument();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;                xDocument.RemoveNamespaceAttributes();&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;                return new XmlDocument().CreateCDataSection(xDocument.ToString());&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;            set =&amp;gt; _ = value; // Without an explicit setter the serializer ignores this&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;        [XmlIgnore]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;        public SampleNestedObject SampleNestedObjectInternal { get; set; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    public class SampleNestedObject&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;        [XmlElement(ElementName = &amp;quot;Name&amp;quot;)]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;        public string Name { get; set; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This code shows an example of how to serialize an object to XML and include a property that contains a CDATA section. In this case, the object being serialized is &lt;code class=&quot;language-text&quot;&gt;SampleObject&lt;/code&gt;, which contains a nested object of type &lt;code class=&quot;language-text&quot;&gt;SampleNestedObject&lt;/code&gt;. This code can be useful when working with SOAP services that expect CDATA sections in their XML payloads. The &lt;code class=&quot;language-text&quot;&gt;Transaction&lt;/code&gt; field in the &lt;code class=&quot;language-text&quot;&gt;SampleObject&lt;/code&gt; is required to be CDATA and to achieve this we create a property for the SampleNestedObject with the &lt;code class=&quot;language-text&quot;&gt;XmlIgnore&lt;/code&gt; attribute, then a separate utility that does the bidding to CDATA&lt;/p&gt;
&lt;p&gt;If we were to serialize this, we would get the following xml&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;12&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SampleObject&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns:xsi&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns:xsd&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://schemas.xmlsoap.org/soap/envelope/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;CDataSection&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;lt;![CDATA[&amp;lt;SampleNestedObject xmlns:xsi=&amp;quot;http://www.w3.org/2001/XMLSchema-instance&amp;quot; xmlns:xsd=&amp;quot;http://www.w3.org/2001/XMLSchema&amp;quot; xmlns=&amp;quot;http://schemas.xmlsoap.org/soap/envelope/&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;    &amp;lt;Name&amp;gt;Dummy&amp;lt;/Name&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;  &amp;lt;/SampleNestedObject&amp;gt;]]&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;CDataSection&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SampleObject&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice that we used the extension &lt;code class=&quot;language-text&quot;&gt;RemoveNamespaceAttributes&lt;/code&gt;, to avoid getting an empty namespace sections on the CData section, specifically getting back the following:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;13&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SampleObject&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns:xsi&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot; http:// www.w3.org/ 2001/ XMLSchema-instance&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns:xsd&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot; http:// www.w3.org/ 2001/ XMLSchema&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot; http:// schemas.xmlsoap.org/ soap/ envelope/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;CDataSection&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;lt;![CDATA[&amp;lt;SampleNestedObject&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;    &amp;lt;Name&amp;gt;Dummy&amp;lt;/Name&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;  &amp;lt;/SampleNestedObject&amp;gt;]]&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;CDataSection&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;SampleObject&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This uses the following extension method:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;14&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RemoveNamespaceAttributes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;XDocument&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xDocument&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xDocument&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Descendants&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Attributes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;IsNamespaceDeclaration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;elem&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xDocument&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Descendants&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;elem&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;elem&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;LocalName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The method works by using LINQ to iterate over all elements in the document, removing the namespace attributes, and then setting the element name to only the local name (i.e., without the namespace). This essentially flattens the document, removing all references to namespaces.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Note that removing namespace attributes can have unintended consequences, such as removing the ability to distinguish between two elements with the same local name in different namespaces. Therefore, this method should be used with caution and only when necessary.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk17 { color: #808080; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[How to Create SOAP Requests Using Postman]]></title><description><![CDATA[Photo by Mika Baumeister on Unsplash How to Create SOAP Requests Using Postman Postman is a popular tool used to test APIs and make HTTP…]]></description><link>http://www.drunkonmonads.com/SOAP with Postman/</link><guid isPermaLink="false">http://www.drunkonmonads.com/SOAP with Postman/</guid><pubDate>Thu, 09 Mar 2023 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@mbaumi?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Mika Baumeister&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/WOn90Iui_08?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;How to Create SOAP Requests Using Postman&lt;/h1&gt;
&lt;p&gt;Postman is a popular tool used to test APIs and make HTTP requests. It can also be used to make SOAP requests, which is a messaging protocol used to exchange structured information between web applications. In this blog post, I will guide you on how to create SOAP requests using Postman.&lt;/p&gt;
&lt;h2&gt;Step 1: Enter Your SOAP Endpoint&lt;/h2&gt;
&lt;p&gt;To make a SOAP request, you will need to enter your SOAP endpoint URL in the address field of a new request tab in Postman. Select the POST method from the request method dropdown list. For example, we will use the following endpoint URL: &lt;code class=&quot;language-text&quot;&gt;https://www.dataaccess.com/webservicesserver/NumberConversion.wso&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;a href=&quot;https://www.dataaccess.com/webservicesserver/NumberConversion.wso&quot;&gt;NumberConversion&lt;/a&gt; has a service, &lt;a href=&quot;https://www.dataaccess.com/webservicesserver/NumberConversion.wso?op=NumberToWords&quot;&gt;NumberToWords&lt;/a&gt;, which returns the word corresponding to the positive number passed as parameter limited to quadrillions. Due to its simplicity we will use it in this example&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Step 2: Add Body Data&lt;/h2&gt;
&lt;p&gt;In the Body tab, select &lt;code class=&quot;language-text&quot;&gt;raw&lt;/code&gt; and choose &lt;code class=&quot;language-text&quot;&gt;XML&lt;/code&gt; from the dropdown list. Enter your XML in the text entry area. Your request body must include the &lt;code class=&quot;language-text&quot;&gt;SOAP Envelope&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Header&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;Body&lt;/code&gt; tags as required by the endpoint, as well as any namespaces. The data needs to include the name of the operation, together with any values you need to post to the service.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; encoding&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Envelope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns:soap&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://schemas.xmlsoap.org/soap/envelope/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Body&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;NumberToWords&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://www.dataaccess.com/webservicesserver/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ubiNum&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;500&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ubiNum&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;NumberToWords&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Body&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Envelope&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Step 3: Set Your Request Headers&lt;/h2&gt;
&lt;p&gt;When you select an &lt;code class=&quot;language-text&quot;&gt;XML&lt;/code&gt; body type, Postman automatically adds a &lt;code class=&quot;language-text&quot;&gt;Content-Type&lt;/code&gt; header of &lt;code class=&quot;language-text&quot;&gt;application/xml&lt;/code&gt;. However, depending on your service provider, you may need &lt;code class=&quot;language-text&quot;&gt;text/xml&lt;/code&gt; for some SOAP requests. Check with your SOAP service to decide which header is appropriate. If you need the &lt;code class=&quot;language-text&quot;&gt;text/xml&lt;/code&gt; header or otherwise, you will need to override the default setting added by Postman.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can also include the character set in the &lt;code class=&quot;language-text&quot;&gt;Content-Type&lt;/code&gt; header, for example, &lt;code class=&quot;language-text&quot;&gt;text/xml; charset=utf-8&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For the number conversion SOAP API example, you need to change the content type header to text/xml. To set request headers, do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Open the request Headers. If the auto-generated headers are hidden, select the notice to display them.&lt;/li&gt;
&lt;li&gt;Deselect the &lt;code class=&quot;language-text&quot;&gt;Content-Type&lt;/code&gt; header Postman added automatically.&lt;/li&gt;
&lt;li&gt;Add a new row with &lt;code class=&quot;language-text&quot;&gt;Content-Type&lt;/code&gt; in the Key field and &lt;code class=&quot;language-text&quot;&gt;text/xml&lt;/code&gt; in the Value field.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Step 4: Send Your Request&lt;/h2&gt;
&lt;p&gt;Select Send to make your call to the SOAP service. If your call is successful, Postman displays the response in the lower tab. You can inspect the response to verify that your SOAP request was processed correctly.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; encoding&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Envelope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns:soap&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://schemas.xmlsoap.org/soap/envelope/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Body&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;m:NumberToWordsResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;xmlns:m&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;http://www.dataaccess.com/webservicesserver/&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;m:NumberToWordsResult&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;five hundred &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;m:NumberToWordsResult&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;m:NumberToWordsResponse&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Body&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;soap:Envelope&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In conclusion, Postman makes it easy to create SOAP requests and test SOAP APIs. By following the steps outlined in this blog post, you can make SOAP requests in Postman with ease.&lt;/p&gt;
&lt;p&gt;Here is the complete curl you can import in Postman to skip the steps highlighted.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;curl&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;curl --location &amp;#39;https://www.dataaccess.com/webservicesserver/NumberConversion.wso&amp;#39; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;--header &amp;#39;Content-Type: text/xml; charset=utf-8&amp;#39; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;--data &amp;#39;&amp;lt;?xml version=&amp;quot;1.0&amp;quot; encoding=&amp;quot;utf-8&amp;quot;?&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;lt;soap:Envelope xmlns:soap=&amp;quot;http://schemas.xmlsoap.org/soap/envelope/&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  &amp;lt;soap:Body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    &amp;lt;NumberToWords xmlns=&amp;quot;http://www.dataaccess.com/webservicesserver/&amp;quot;&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;      &amp;lt;ubiNum&amp;gt;500&amp;lt;/ubiNum&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    &amp;lt;/NumberToWords&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  &amp;lt;/soap:Body&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;lt;/soap:Envelope&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk17 { color: #808080; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Clean Architecture]]></title><description><![CDATA[Photo by Kimon Maritz on Unsplash Clean Architecture This article summarizes the principles of Clean Architecture based on my own…]]></description><link>http://www.drunkonmonads.com/clean-architecture/</link><guid isPermaLink="false">http://www.drunkonmonads.com/clean-architecture/</guid><pubDate>Tue, 07 Mar 2023 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@kimonmaritz?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Kimon Maritz&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/mQiZnKwGXW0?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Clean Architecture&lt;/h1&gt;
&lt;p&gt;This article summarizes the principles of Clean Architecture based on my own experiences using this architecture in different scenarios. Robert C. Martin’s &lt;a href=&quot;https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/&quot;&gt;book&lt;/a&gt; on this topic was an anchor to my understanding of this topic, especially having discovered the book after working on the architecture for a while. I recently read the book again as a refresher before creating this article and therefore this article serves as a summary of the good parts and additions from my own experiences.&lt;/p&gt;
&lt;h1&gt;Architecture&lt;/h1&gt;
&lt;p&gt;When considering architecture, it is crucial to keep in mind several important factors.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;First and foremost, the system’s life cycle should be supported, which involves ensuring that it can be maintained, upgraded, and expanded as needed with minimal complications.&lt;/li&gt;
&lt;li&gt;Additionally, the system’s lifetime cost should be minimized to keep it viable for as long as possible. A well-designed architecture should also prioritize maximizing programmer productivity by enabling them to work more efficiently and effectively.&lt;/li&gt;
&lt;li&gt;Finally, the architecture should make the operation of the system apparent to developers, who need a clear understanding of how the system works and how it is intended to be used. This is achieved by elevating the use cases, features, and required behaviours of the system to first-class entities that serve as visible landmarks for developers.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is important to recognize that among all aspects of a software system, maintenance tends to be the most expensive. This is mainly due to two factors: spelunking and risk.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/98c76574b5a01f2d5bb0aa05639c21f0/120d2/bobby-stevenson-lKzNVOHNq0U-unsplash.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 150%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAeABQDASIAAhEBAxEB/8QAGgAAAgIDAAAAAAAAAAAAAAAAAAgHCQMFBv/EABgBAAIDAAAAAAAAAAAAAAAAAAcIAwQG/9oADAMBAAIQAxAAAAGiy85DZvWtnVqFuCaNnbXqBOZlv7Exm6FH/8QAHBAAAgIDAQEAAAAAAAAAAAAABAUDBgABAgcS/9oACAEBAAEFAlawxwdRqGFCpItW62bRa7sALz/0J0Sxcm9mNyWSlRFU7UvrHcv33KeaQXNmppM//8QAJREAAgIBAwIHAQAAAAAAAAAAAQMCBAUGERMAIgcSFBUhIzFS/9oACAEDAQE/AdA6eXo6qj3KLlah1amzVpxFR1riTWUboqw9PGfkDorVZdZlyQZDiCl8C22un61zVd70VciV1kuauus08L2JgwxXD7sfNoEYgABk5TAG0pEjfrP+K2St56llsXTqU2Yhl0Y+bIMdPjtrNZ4eubZJlJqB88cFhZmQrbjUYyYuUjIynvIknsH6Tv8A31//xAAjEQACAgICAgEFAAAAAAAAAAACAwEEBREGEhMhAAciI0Fh/9oACAECAQE/AfqplctyddtODasMVxttaxeKbSqjGzYMK3n7vJcT0JhoWgZAg02WM8zFVpr8MwlhCH3aBNttQllpg38wMMsEsJaek3wV9x7n8YAPv0Mb18x3A6Q467TyFh9qMoKJujEgAySGeZPjIQhnVRzoYOS7wEd99zgoA4iIgQ1EREe5/Wv58//EACoQAAMAAgIABgECBwAAAAAAAAECAwQRBRIAExQhIjIxEGEVQUJRYoGR/9oACAEBAAY/AocfgoHyLt1Xses0H86Vf+ia7HZv3AG2IHjjcKvlVj6J4CiMlBWpPk5L6Q77HId/t5Z0dbG+w5DhP4DhcovH5+VjTyvX3+samXk/JaMBBkaYUt8AOg+Kjxk13PzuQKmWQqn1D4bRnWOMJN1ti7qx9VMjvQACVB9hy/GS4iAHDWEcfWZHGxuPim8Yo59P5+XRbRvkTaMe/UaKjXbxymTk06XtyGY9BLYTsbvsjZ2dn8sdlz8iffwiPycoWtjmloRcu2Hlq7IHsoDqFUBG6tTzFIKBTv5Zi0OTVuQrh3a46MYumCzVarezUV8zIdRNR2RF7PtvY0fRPd2ffRvcsdk/7J8ZVLv2pfJrap/vR6M76/x7fj9gP0+x/wCnx//EAB0QAQADAAIDAQAAAAAAAAAAAAEAESExcUFRodH/2gAIAQEAAT8h9YNwhhJvA5DTbG7CUzTUqalYF04xnUopKaiJK/s27uBBg+UCFMVTBC51v5KtTZdk2K4bWOoGLlZKpnpv17CrDhwlzReCVNuknosxpTIJYIQeBnRYs+WrEsLgEsjy9/kCB4/LP19Z0E//2gAMAwEAAgADAAAAEDfZP//EABoRAQEAAgMAAAAAAAAAAAAAAAERACExQWH/2gAIAQMBAT8QIjVhByACw+pmaiTcEUFm/s24MBEU770k5iE4S5VAEi8osvve7//EABoRAQEAAwEBAAAAAAAAAAAAAAERACExQaH/2gAIAQIBAT8QpkoT3SyugGs4Ji0lPjV3qqTgDu5X+moMzrHKbkhAtAHJ4ea+3//EABsQAQEBAQEAAwAAAAAAAAAAAAERIQAxQWFx/9oACAEBAAE/ECYp9ag6kIlxgKVPdJ6sHVoNnO6P0FTQg2WwSCBOOYktm4gvDVtOyXgY10NabXcBuhLi6i8/0LPZpcg9rRVjWr4U0ALO7d5FfceUCABAAU0C+CR+wOigUlpWr3SrTH5339t4DPAVJPKq5ACAAMr/AP/Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;bobby stevenson lKzNVOHNq0U unsplash&quot;
        title=&quot;&quot;
        src=&quot;/static/98c76574b5a01f2d5bb0aa05639c21f0/451a4/bobby-stevenson-lKzNVOHNq0U-unsplash.jpg&quot;
        srcset=&quot;/static/98c76574b5a01f2d5bb0aa05639c21f0/953fe/bobby-stevenson-lKzNVOHNq0U-unsplash.jpg 500w,
/static/98c76574b5a01f2d5bb0aa05639c21f0/0a251/bobby-stevenson-lKzNVOHNq0U-unsplash.jpg 1000w,
/static/98c76574b5a01f2d5bb0aa05639c21f0/451a4/bobby-stevenson-lKzNVOHNq0U-unsplash.jpg 2000w,
/static/98c76574b5a01f2d5bb0aa05639c21f0/c7e40/bobby-stevenson-lKzNVOHNq0U-unsplash.jpg 3000w,
/static/98c76574b5a01f2d5bb0aa05639c21f0/120d2/bobby-stevenson-lKzNVOHNq0U-unsplash.jpg 4000w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;©️ Photo by &lt;a href=&quot;https://unsplash.com/@bobbystevenson?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Bobby Stevenson&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/lKzNVOHNq0U?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Spelunking involves the cost of thoroughly examining the existing software to identify the most suitable approach for implementing new features or resolving defects. However, such changes can also raise the risk of inadvertently introducing new defects, thereby contributing to the overall cost.&lt;/p&gt;
&lt;h2&gt;Good Architecture&lt;/h2&gt;
&lt;p&gt;A sound architecture seeks to maintain as many options open for as long as possible. In light of this, it is critical to note that all decisions are trade-offs, and the context plays a pivotal role. An architecture that enables deferring decisions is generally favourable. The elements that require extended options include insignificant details such as database implementation specifics, web services, frameworks, and communication protocols.&lt;/p&gt;
&lt;p&gt;Effective architecture renders the system simple to comprehend, develop, maintain, and deploy.&lt;/p&gt;
&lt;p&gt;A well-designed architecture should be expressive (screams 😱), drawing attention to critical boundaries and highlighting use cases.&lt;/p&gt;
&lt;h1&gt;Important terminology&lt;/h1&gt;
&lt;h2&gt;Policy vs Details&lt;/h2&gt;
&lt;p&gt;To ensure clarity in our discussion, it’s important to establish some recurring terminology.&lt;/p&gt;
&lt;p&gt;In all software systems, two fundamental components can be identified: policy and details.&lt;/p&gt;
&lt;p&gt;The policy encompasses all the business rules and procedures that represent the real value of the system.&lt;/p&gt;
&lt;p&gt;The details refer to the elements required to interact with the policy but do not have an impact on the policy’s behaviour. These may include database implementations, web systems, and communication protocols.&lt;/p&gt;
&lt;p&gt;The objective is to prioritize the policy component as the most vital part of the system while ensuring that the details are irrelevant to the policy’s behaviour. This approach enables decisions about the details to be postponed.&lt;/p&gt;
&lt;h1&gt;Clean Architecture Brief&lt;/h1&gt;
&lt;p&gt;Clean Architecture aims to create systems that are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Independent of frameworks&lt;/li&gt;
&lt;li&gt;Independent of the user interface&lt;/li&gt;
&lt;li&gt;Independent of the database&lt;/li&gt;
&lt;li&gt;Independent of any external agencies for that matter like 3rd party services you may consume via SDKs or APIs&lt;/li&gt;
&lt;li&gt;Testable, more specifically, easily testable&lt;/li&gt;
&lt;li&gt;Easy to understand, build and maintain. It should be easy for developers to comprehend how the system works, and the design should facilitate changes and updates without introducing undue complexity&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;S.O.L.I.D principles&lt;/h1&gt;
&lt;p&gt;To have a complete understanding and appreciation of Clean Architecture, it’s crucial to have a solid foundation in certain building blocks. Therefore, we will take a comprehensive approach, beginning with the SOLID principles.&lt;/p&gt;
&lt;p&gt;Clean code is fundamental to building effective software systems, and the SOLID principles are instrumental in achieving this goal.&lt;/p&gt;
&lt;p&gt;The SOLID principles are a set of guidelines that aim to create modules in a software system that can be changed with minimal cost or friction, are easy to understand, and have a high potential for reuse.&lt;/p&gt;
&lt;p&gt;SOLID is an acronym for five principles, which are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Single Responsibility Principle (SRP) - A module should have only one reason to change, meaning it should have only one responsibility.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Open/Closed Principle (OCP) - A module should be open for extension but closed for modification. This means that the behaviour of a module can be extended without changing its source code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Liskov Substitution Principle (LSP) - A sub-type should be substitutable for its base type. This means that any object of a base class should be replaceable with an object of its derived class without altering the correctness of the program.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Interface Segregation Principle (ISP) - A client should not be forced to implement interfaces they do not use. This means that the interface of a module should be specific to the needs of the client.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dependency Inversion Principle (DIP) - High-level modules should not depend on low-level modules. Both should depend on abstractions. This means that a module should not depend on the details of another module but rather on its abstractions. It’s important to note that the emphasis is on inversion and not injection in DIP. We will cover this in more detail later.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Single Responsibility Principle&lt;/h2&gt;
&lt;p&gt;The Single Responsibility Principle (SRP) is often misunderstood and incorrectly defined as &lt;code class=&quot;language-text&quot;&gt;A module must do one and only one thing
&lt;/code&gt;. The principle is derived from Conway’s law, which suggests that software systems are heavily influenced by the social structures of the organization that uses them.&lt;/p&gt;
&lt;p&gt;The correct definition of SRP is that a module should have only one reason to change, meaning that it should only honour one actor. In other words, a module should have a single responsibility, but that responsibility may involve multiple functions.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c955db94746c17b5527c9f240aa87d9a/80150/erik-mclean-qsvQfsSUOgk-unsplash.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.60000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAANABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAgHCf/EABQBAQAAAAAAAAAAAAAAAAAAAAL/2gAMAwEAAhADEAAAAezeT0FP6Fbgv//EABsQAAEFAQEAAAAAAAAAAAAAAAYAAgMFBwEW/9oACAEBAAEFAj0r8SJhehtNLlErY3DtVyGbQl//xAAbEQACAQUAAAAAAAAAAAAAAAABERIQIVGRwf/aAAgBAwEBPwEykLiOEXt8p//EABwRAAIABwAAAAAAAAAAAAAAAAEREBIhMUFRcf/aAAgBAgEBPwEKU0L2whbC7D//xAAjEAADAQABAwMFAAAAAAAAAAABAgMEBQAREgYhIgcQExQV/9oACAEBAAY/AuY9TDj6cq/GSi0uPlZczaraNUcskOh0osJ+dg1bMjeE1Y+JPYdIuXXky5Uycg7cPVXTlaN+PgtEbOKL7pxw20z6KZ2MHpqiQWHj2650VlO0/wCPyZeVVDzoBis3i6n2Knt1HSITnWGL1ZgmUAXtm/X+nWwJ2UKPi+llHcEhVABA+P2//8QAGhABAQACAwAAAAAAAAAAAAAAAREAIRAxof/aAAgBAQABPyFjfogLcY8ZCoj6X6GGlnQc/wANQ5xi1KoKJ7nfh3uHwihpRKz/2gAMAwEAAgADAAAAENgP/8QAGBEBAQEBAQAAAAAAAAAAAAAAAREhEDH/2gAIAQMBAT8Q8MILoKpYIBiFVo48/8QAGBEBAQEBAQAAAAAAAAAAAAAAAREhMRD/2gAIAQIBAT8Q6ibggBApVekRCTfP/8QAGBABAAMBAAAAAAAAAAAAAAAAAQAQESH/2gAIAQEAAT8QkbTeA/fqCEwJQyjGl+jxfUG8JCy45FOcxMAiFdilAArO3qf/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;erik mclean qsvQfsSUOgk unsplash&quot;
        title=&quot;&quot;
        src=&quot;/static/c955db94746c17b5527c9f240aa87d9a/451a4/erik-mclean-qsvQfsSUOgk-unsplash.jpg&quot;
        srcset=&quot;/static/c955db94746c17b5527c9f240aa87d9a/953fe/erik-mclean-qsvQfsSUOgk-unsplash.jpg 500w,
/static/c955db94746c17b5527c9f240aa87d9a/0a251/erik-mclean-qsvQfsSUOgk-unsplash.jpg 1000w,
/static/c955db94746c17b5527c9f240aa87d9a/451a4/erik-mclean-qsvQfsSUOgk-unsplash.jpg 2000w,
/static/c955db94746c17b5527c9f240aa87d9a/c7e40/erik-mclean-qsvQfsSUOgk-unsplash.jpg 3000w,
/static/c955db94746c17b5527c9f240aa87d9a/120d2/erik-mclean-qsvQfsSUOgk-unsplash.jpg 4000w,
/static/c955db94746c17b5527c9f240aa87d9a/80150/erik-mclean-qsvQfsSUOgk-unsplash.jpg 5220w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;©️ Photo by &lt;a href=&quot;https://unsplash.com/@introspectivedsgn?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Erik Mclean&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/qsvQfsSUOgk?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the given example, there is a violation of the Single Responsibility Principle, as there is a coupling between concerns from different actors.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Customer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// data fields&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CalculateDeliveryCost&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;dynamic&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ReportNextDelivery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () {}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Save&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The Calculate Delivery Cost function may be intended for the accounting department, which reports to the CFO. The Get Next Delivery Details function may be intended for the delivery department, which reports to the COO. The Save function may be specified by the database administrators who report to the CTO.&lt;/p&gt;
&lt;p&gt;The proximity of the code may encourage premature reuse. For example, the calculation of delivery costs may depend on a method that filters deliveries. The delivery team may choose to modify the shared code to exclude deliveries from a collection centre in a postal code that already has other deliveries due on the same day. However, this change may have unintended consequences for accounting, resulting in incorrect reporting and potentially leading to a disgruntled CFO.&lt;/p&gt;
&lt;p&gt;This example illustrates the importance of adhering to the Single Responsibility Principle to avoid such coupling of concerns from different actors and the resulting problems.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Customer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// data fields&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DeliveryCostCalculator&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CalculateDeliveryCost&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDeliveryReporter&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;dynamic&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ReportNextDelivery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IEmployeeRepository&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Save&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Customer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;customer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To address the violation of the Single Responsibility Principle in the previous example, one solution could be to adopt an anaemic model, which is favoured in functional programming. In this approach, the behaviour is offloaded from the data, and each component has a single responsibility.&lt;/p&gt;
&lt;p&gt;For example, instead of having a Delivery object with methods like CalculateDeliveryCost and GetNextDeliveryDetails, we could have a DeliveryData object that only holds the delivery data and separate classes that handle the behaviours associated with the data.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CalculateDeliveryCostUseCase&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDeliveryCostCalculator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;deliveryCostCalculator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ReportNextDeliveryUseCase&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Execute&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDeliveryReporter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;deliveryReporter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example of using an anaemic model to adhere to the Single Responsibility Principle, we can offload the orchestration of the new moving parts into a use case. The use case is a separate component that is responsible for handling the interactions between the different parts of the system, making the actions explicit and enforcing SRP through a single Execute method.&lt;/p&gt;
&lt;p&gt;Although it’s possible to directly call through the newly added abstraction, it’s often beneficial to use a use case to orchestrate the interactions between the components. This is because use cases are great at handling application-specific concerns and orchestrating complex interactions.&lt;/p&gt;
&lt;p&gt;For example, imagine that we want to send emails after the delivery cost is calculated. Ideally, this should not be added to the DeliveryCostCalculator as it can make the component less reusable. A use case is better suited for this scenario as it can handle this application-specific concern without dirtying the DeliveryCostCalculator.&lt;/p&gt;
&lt;p&gt;Therefore, services should be kept generic, while use cases can be tailored to specific application needs. By using use cases, we can achieve a more modular, maintainable, and reusable system.&lt;/p&gt;
&lt;p&gt;This would result in each component having a single reason to change, making the system more modular and easier to maintain. By offloading the behaviour from the data, we can achieve a more clear separation of concerns and better adhere to the Single Responsibility Principle.&lt;/p&gt;
&lt;h2&gt;Open-Closed Principle&lt;/h2&gt;
&lt;p&gt;The Open/Closed Principle (OCP) states that software systems should be designed to allow for changes in behaviour by adding new code, rather than modifying existing code. The idea is to make the system easy to extend without having a significant impact on the existing codebase.&lt;/p&gt;
&lt;p&gt;To achieve this goal, the system should be partitioned into components, and these components should be organized into a dependency hierarchy that protects higher-level components from changes in lower-level components. For instance, the business rules should remain unaffected when switching to a different database implementation.&lt;/p&gt;
&lt;p&gt;Would you knock down the Burj Khalifa to install a sewage system? The answer is obviously no! Yet as software engineers, we knock down the Burj Khalifa all the time. This analogy highlights the importance of preserving the existing codebase while still allowing for changes and extensions. A well-designed system should strike a balance between preserving the existing code and allowing for future enhancements. This is where the OCP comes into play, as it provides a guideline for designing systems that are easy to extend without having to modify the existing codebase.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0b78272ec453bea8d3d59206bf91bcb4/1a42a/mohit-kumar-6M9xiVgkoN0-unsplash.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 47%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAJABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAUGB//EABcBAAMBAAAAAAAAAAAAAAAAAAIDBAf/2gAMAwEAAhADEAAAAYqgVaRmb4caBTf/xAAcEAABAwUAAAAAAAAAAAAAAAACAAEEAxEUMjP/2gAIAQEAAQUCjCOS1KyYRZQukLVf/8QAIREAAQIEBwAAAAAAAAAAAAAAAgERAAMhQRIUMmOSsdL/2gAIAQMBAT8BRkkmraRxNVicpYsSXZFp1dMtuHyL1H//xAAfEQACAQQDAQEAAAAAAAAAAAABEQIDEiExAAQUIkH/2gAIAQIBAT8B69P0dmnAysNRSvA05TiBa7fkU1oYKxvnkqjXbqpDCBWBhkkoaD/Of//EACYQAAIBAwMDBAMAAAAAAAAAAAECEQMSIQAiMQQTIzJCc7GChLL/2gAIAQEABj8CaAY3eM7lMgmnTN3q9i3NlcMGUEnRsufPlkEhHuPEAcAsTTh043EnGeptU5p94U6VR6fAqMg7kM0G7I3XCIif1W+hpPg6j6Oh+X9tr//EABkQAQEAAwEAAAAAAAAAAAAAAAERACExEP/aAAgBAQABPyGvDRm70SkdSANEFc5QWRSGKc02RMn6WrU1FKGykgQsc/KfPMP/2gAMAwEAAgADAAAAEAwv/8QAGREBAAMBAQAAAAAAAAAAAAAAAREhMQBB/9oACAEDAQE/EADEqw6hC+ikAksnEG4bcApMMDGeSnf/xAAXEQEBAQEAAAAAAAAAAAAAAAABESEA/9oACAECAQE/EEtCep1DqACIqKDmAHQKEpCjShSBWV//xAAYEAEBAQEBAAAAAAAAAAAAAAABEQAgMf/aAAgBAQABPxBDSvbSUjcD5go91vqt3OrItXpKpm3DE1IhuMesqT3/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;mohit kumar 6M9xiVgkoN0 unsplash&quot;
        title=&quot;&quot;
        src=&quot;/static/0b78272ec453bea8d3d59206bf91bcb4/451a4/mohit-kumar-6M9xiVgkoN0-unsplash.jpg&quot;
        srcset=&quot;/static/0b78272ec453bea8d3d59206bf91bcb4/953fe/mohit-kumar-6M9xiVgkoN0-unsplash.jpg 500w,
/static/0b78272ec453bea8d3d59206bf91bcb4/0a251/mohit-kumar-6M9xiVgkoN0-unsplash.jpg 1000w,
/static/0b78272ec453bea8d3d59206bf91bcb4/451a4/mohit-kumar-6M9xiVgkoN0-unsplash.jpg 2000w,
/static/0b78272ec453bea8d3d59206bf91bcb4/c7e40/mohit-kumar-6M9xiVgkoN0-unsplash.jpg 3000w,
/static/0b78272ec453bea8d3d59206bf91bcb4/120d2/mohit-kumar-6M9xiVgkoN0-unsplash.jpg 4000w,
/static/0b78272ec453bea8d3d59206bf91bcb4/1a42a/mohit-kumar-6M9xiVgkoN0-unsplash.jpg 4800w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;©️ Photo by &lt;a href=&quot;https://unsplash.com/@98mohitkumar?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Mohit Kumar&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/6M9xiVgkoN0?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the given example, we have an Order class with a method called CalculateTotal, which calculates the total cost of an order. However, the method violates the Open/Closed Principle because it’s not closed for modification.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Order&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;decimal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CalculateTotal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;decimal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TotalAmount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -= &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TotalAmount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; * &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0.05m&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DiscountPercentage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -= &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TotalAmount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; * &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DiscountPercentage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; / &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we want to add a new type of discount, such as a “buy one, get one free” offer, we would need to modify the CalculateTotal method to include this new type of discount. This violates the OCP because we are modifying existing code rather than extending it.&lt;/p&gt;
&lt;p&gt;To adhere to the OCP, we could introduce a Discount class that implements a Discount interface, using the strategy pattern. The Discount interface could have a Calculate method, which calculates the discount based on the order. The CalculateTotal method in the Order class could then be modified to use the Discount interface, allowing for the addition of new discount types without modifying the Order class.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDiscountStrategy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;decimal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CalculateDiscount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;decimal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;totalAmount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Order&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;decimal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CalculateTotal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;decimal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DiscountStrategy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; != &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -= &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DiscountStrategy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CalculateDiscount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TotalAmount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PercentageDiscountStrategy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDiscountStrategy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;decimal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Percentage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;decimal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CalculateDiscount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;decimal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;totalAmount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// calculate the discount for percentage offer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BuyOneGetOneFreeDiscountStrategy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDiscountStrategy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;decimal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CalculateDiscount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;decimal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;totalAmount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// calculate the discount for buy one, get one free offer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;By doing this, we ensure that the Order class is closed for modification and open for extension, as new discount types can be added by implementing the Discount interface, without changing the Order class itself. This makes the system more modular, flexible, and easier to maintain.&lt;/p&gt;
&lt;p&gt;Let’s look at another violation. In the given example of a reporting service that pulls data out of a database, massages the data, and sends out an email report with an excel file attached, there is a violation of the Open/Closed Principle.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1196px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/39fe48fcddd3fb47d67f29621897a887/d6bb7/ocp-violation.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 37.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAHABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAQGCf/EABUBAQEAAAAAAAAAAAAAAAAAAAUG/9oADAMBAAIQAxAAAAHY6+Cx0UTyv//EABkQAAIDAQAAAAAAAAAAAAAAAAMFAgQGE//aAAgBAQABBQJd022aUpRKK889TIT/xAAgEQACAgEDBQAAAAAAAAAAAAABAgMEABESEyEiQlGR/9oACAEDAQE/AaUSSQU7cg5LL04N8zAbnLRIWJChU6k69qgegM5ZD5t9z//EACARAQACAgIBBQAAAAAAAAAAAAECAwQRACEFEhMUImH/2gAIAQIBAT8B8nfZTleQwKZNWFXn5Xt40VYQIXzIAzZWPpABlOUnX2V744OGq/Gq2rJ1AO12ujrt7f3n/8QAIhAAAgIBBAEFAAAAAAAAAAAAAgMBBAUAERITQhQhIjJS/9oACAEBAAY/AqNq8WSwbW2bDCXiMqxDo9JZtVBGbaYiTU0R7TVtx58fxGirhdyt+CfL+3KZB954zIgPWDWTEwmOuChf1giMvKdNabbJk1hM+ZJPhy8A5IkoXHiMzO28++v/xAAaEAEBAAIDAAAAAAAAAAAAAAABEQAxIUFh/9oACAEBAAE/IWxlMCP0agD2Ejovtn8jB7IyS1NicLdq1R7DP//aAAwDAQACAAMAAAAQdB//xAAZEQEAAgMAAAAAAAAAAAAAAAABEXEAIZH/2gAIAQMBAT8QPupME04XIGXQAF0rMBQAOABRn//EABYRAQEBAAAAAAAAAAAAAAAAAAERIf/aAAgBAgEBPxAIAxVxcgkwFZSxGMA5sAawCpXVv//EABcQAQEBAQAAAAAAAAAAAAAAAAEhABH/2gAIAQEAAT8QTF7H8d5fMGmxstJ1eI7woKEabXlYEgwBDMJA/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;ocp violation&quot;
        title=&quot;&quot;
        src=&quot;/static/39fe48fcddd3fb47d67f29621897a887/d6bb7/ocp-violation.jpg&quot;
        srcset=&quot;/static/39fe48fcddd3fb47d67f29621897a887/953fe/ocp-violation.jpg 500w,
/static/39fe48fcddd3fb47d67f29621897a887/0a251/ocp-violation.jpg 1000w,
/static/39fe48fcddd3fb47d67f29621897a887/d6bb7/ocp-violation.jpg 1196w&quot;
        sizes=&quot;(max-width: 1196px) 100vw, 1196px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Suppose we want to display the reports on the web or print them out. In that case, we would need to modify the existing code to accommodate these changes, violating the OCP.&lt;/p&gt;
&lt;p&gt;To adhere to the OCP, we can introduce a Report class that takes care of generating the report data, and separate ReportFormatter classes for each output format (e.g., EmailReportFormatter, WebReportFormatter, PrintReportFormatter). The ReportFormatter classes implement a ReportFormatter interface that has a format method. The format method takes in the Report data and generates the output in the desired format.&lt;/p&gt;
&lt;p&gt;By doing this, we can add new output formats without modifying the existing Report class, making the system closed for modification and open for extension. This approach makes the system more modular, flexible, and easier to maintain.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 722px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0b8af0241b2c8f20524c5223ca3a6300/f6f8c/ocp-violation-fix.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 77.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAQABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAYFCf/EABUBAQEAAAAAAAAAAAAAAAAAAAUG/9oADAMBAAIQAxAAAAHudL4Fk0UUqfX/AP/EABkQAQEAAwEAAAAAAAAAAAAAAAQFAgMGFf/aAAgBAQABBQK41E6XzVdtoUNc6iUOl9+Vz0PxBiMjRj//xAAeEQACAgICAwAAAAAAAAAAAAABAgMRBBITMQAhkf/aAAgBAwEBPwFHyp8uCdFdcNsdtgZIGHJu1XxTSWWXUgpstEWwNqJPcjGwbN2Lo9dWAfo8/8QAHhEAAgIDAQADAAAAAAAAAAAAAQIDBBESE0EABSH/2gAIAQIBAT8BkjpVqFqtI8T/AGKW00ZYrKniY4y2O9aIqFbZWWTm2wJVWUqzVUMNeGL9HNFXBxkY8OhK+eE/P//EACQQAAICAQMEAgMAAAAAAAAAAAIDAQQFERITACEiMQYVI0FR/9oACAEBAAY/ArlyqAG9CeRYsTasBM8ix8k0xKyfYp7KiS/fqJ6a6+tKzG2aYFVPI1hJYrUcajkRW2dZOYkhGVTHjE7oLp50Laby6961Ua0SWzjsJOOWuUh2glboiR9/3XXrNVbWax2U1s2MUJP+McVWvZx9iU3hsULGRaORUTQjj80hG3eJH0yqf1ZEdgn7sXhkYVXkta/Oul9gWO/H3sScEQ7A26LiZfD3g2WWWtXxr4oFR7doTEkWpRpO4vU6+uv/xAAZEAEBAQEBAQAAAAAAAAAAAAABESEAMXH/2gAIAQEAAT8hcw4YNAF796EWjGUL548RWFjZZenhYhL/ADOKVJgNMjWd+6lBUleC6V/WaUCngM2Dn9Y8tRRcDv/aAAwDAQACAAMAAAAQ/wAv/8QAGBEBAQEBAQAAAAAAAAAAAAAAASERADH/2gAIAQMBAT8QdX8cSMsRHUL6ze1w6HSxKkATzJf/xAAZEQEAAwEBAAAAAAAAAAAAAAABABEhMUH/2gAIAQIBAT8QPG4zw1NGQWNhcUKvWIGlgDNXtz//xAAWEAEBAQAAAAAAAAAAAAAAAAABEQD/2gAIAQEAAT8QVV1stp2KMUyAMV78GVVnlGg618U4X1P03eJ5XyFQElDtjGzJ8PwSedWbwQ0acEHSRROrGj//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;ocp violation fix&quot;
        title=&quot;&quot;
        src=&quot;/static/0b8af0241b2c8f20524c5223ca3a6300/f6f8c/ocp-violation-fix.jpg&quot;
        srcset=&quot;/static/0b8af0241b2c8f20524c5223ca3a6300/953fe/ocp-violation-fix.jpg 500w,
/static/0b8af0241b2c8f20524c5223ca3a6300/f6f8c/ocp-violation-fix.jpg 722w&quot;
        sizes=&quot;(max-width: 722px) 100vw, 722px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Liskov Substitution Principle&lt;/h2&gt;
&lt;p&gt;The Liskov Substitution Principle (LSP) states that objects of a superclass should be replaceable with objects of its subclasses without affecting the correctness of the program. The principle emphasizes the importance of adhering to a contract that allows the parts to be substituted one for another to build software systems from interchangeable parts.&lt;/p&gt;
&lt;p&gt;By following the LSP, we can avoid pollution in the codebase when multiple implementations follow a contract. In other words, we can ensure that different implementations of the same contract behave in the same way, and they can be used interchangeably.&lt;/p&gt;
&lt;p&gt;The LSP is particularly important for achieving modularity and ensuring that the system is easy to extend and maintain. By adhering to the principle, we can make sure that the system remains correct and consistent, even as we add new components or modify existing ones.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/834c7e6a892de59c3be9b82bc66f088e/308e2/derek-steen-8SxsQfeKkHY-unsplash.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAYHBQn/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHp8tXBUK6bAf/EABsQAAICAwEAAAAAAAAAAAAAAAUGAAcBAgQD/9oACAEBAAEFAjl1p4ItrfSt6RZZOFqGF61Rzvbmm62zAwUYvj//xAAXEQADAQAAAAAAAAAAAAAAAAABEGGh/9oACAEDAQE/ARcX/8QAGhEAAQUBAAAAAAAAAAAAAAAAIQEQYXGx0f/aAAgBAgEBPwFYFnmt/8QAJBAAAgICAgIBBQEAAAAAAAAAAQIDBAUSESEAEzEGFDI2crL/2gAIAQEABj8Cu4SdMrPfx9lqllYaaiISoELaTSzRpIB7E5I+Nhz2R4fViPqWYBihaHHxSrsNSRslkg9Oh6+Q3I8GUx8duGH3y1miuw/b2I5oNfYrx7P8bDg89+TZLKYCvYuzsHmnWxdrmSRRr7GSrZhjMhH5yabuQpcsVUj9bUfzk80v+ciPIcXh6iUqMG5jhVpJO3bZ2eWZ5JpXYnuSWR3PQ24A8//EABkQAQADAQEAAAAAAAAAAAAAAAERITEAQf/aAAgBAQABPyETt7ziPDLc8BOYZpnJQDdAkexjH2JSxSKnBrlIv40iE5ScR0J2+6u5BDCjyM85chp8Omt6KwiAf//aAAwDAQACAAMAAAAQmA//xAAeEQACAQMFAAAAAAAAAAAAAAABESExQXEAUaGx8P/aAAgBAwEBPxA1S5NSiwkHre6I9V8oPKGNf//EABwRAQEAAgIDAAAAAAAAAAAAAAERACExoWGBkf/aAAgBAgEBPxCU5qG4F1dAttmkEfGd+p1WfXP/xAAYEAEBAQEBAAAAAAAAAAAAAAABEQAhMf/aAAgBAQABPxCTrkzGe8mENh6gEwo/jLVCJWJ9FWsCAYrp0CQjOUnFZNCG0SVHQjwR0AgehXYzQAoN9kNgkI3/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;derek steen 8SxsQfeKkHY unsplash&quot;
        title=&quot;&quot;
        src=&quot;/static/834c7e6a892de59c3be9b82bc66f088e/451a4/derek-steen-8SxsQfeKkHY-unsplash.jpg&quot;
        srcset=&quot;/static/834c7e6a892de59c3be9b82bc66f088e/953fe/derek-steen-8SxsQfeKkHY-unsplash.jpg 500w,
/static/834c7e6a892de59c3be9b82bc66f088e/0a251/derek-steen-8SxsQfeKkHY-unsplash.jpg 1000w,
/static/834c7e6a892de59c3be9b82bc66f088e/451a4/derek-steen-8SxsQfeKkHY-unsplash.jpg 2000w,
/static/834c7e6a892de59c3be9b82bc66f088e/c7e40/derek-steen-8SxsQfeKkHY-unsplash.jpg 3000w,
/static/834c7e6a892de59c3be9b82bc66f088e/120d2/derek-steen-8SxsQfeKkHY-unsplash.jpg 4000w,
/static/834c7e6a892de59c3be9b82bc66f088e/308e2/derek-steen-8SxsQfeKkHY-unsplash.jpg 6880w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;©️ Photo by &lt;a href=&quot;https://unsplash.com/@djsteen?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Derek Steen&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/8SxsQfeKkHY?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Suppose we have a billing service that generates reports on active licenses, and the service deals with licenses without knowledge of different types of licenses. In this case, different types of licenses can be substituted without affecting the function of the billing service because they all follow the same contract.&lt;/p&gt;
&lt;p&gt;For example, we could have different types of licenses, such as &lt;code class=&quot;language-text&quot;&gt;Corporate License&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Personal License&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Education License&lt;/code&gt; that implement the same interface or extend the same superclass. As long as they adhere to the contract, they can be used interchangeably, without affecting the correctness of the program.&lt;/p&gt;
&lt;p&gt;This is the essence of the LSP: designing software components that follow the same contract, so they can be substituted one for another without affecting the system’s correctness or behaviour. By following the LSP, we can ensure that the system is modular, extensible, and easy to maintain.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 787px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/11251966a20a6a13bd66765e32f3618b/672e7/lsp.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 71.8%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAOABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAgJBgf/xAAWAQEBAQAAAAAAAAAAAAAAAAACBQb/2gAMAwEAAhADEAAAAbtrllmH08HpxPoZ/8QAHRABAAEDBQAAAAAAAAAAAAAABQYAAgMBBAcXIf/aAAgBAQABBQJTPbtzYkziRV09oDmc51uXSXFEhu/D7a//xAAmEQABAgQDCQAAAAAAAAAAAAAEAQIAAwUREhQjExYhJCVBVKTU/9oACAEDAQE/Ac6KZ1Ic7lAMeZ06i26NRHv02Ejy32lqltoITZV4d2xvRQ/O9Yz54//EACURAAEDAgMJAAAAAAAAAAAAAAEDBAUCEQAGExQVFiIjUlWk1P/aAAgBAgEBPwHdz2OvDvI0l/Kaex2WiKrGurSo6qjN4smCqDcIv2VwObvxwVmbxvuR/wBWP//EACYQAAICAAUDBAMAAAAAAAAAAAECAwQABRESEwYUQRYhIiMzNGT/2gAIAQEABj8CzCY3Ow4aVmQ3hD3JpbYXbuu32tzmD8vDtPJt26HXCV268bqaQV3sJTfpo5U4EOgawlmOGFAv2APC6szfHj2aNuxl2TRZJdgkzO2KqTSWYGSM8czbmVUBI+g+wPkYkzmWo9xEsVa/BHIsTE2phEG3srj466kae+NPTlzyf34PJP8APj//xAAbEAACAwEBAQAAAAAAAAAAAAABEQAhMUFRkf/aAAgBAQABPyE8qpiFhFFS4+WX41tkJiKZaEBAARnzK7ezApgXa64ki/IwpCcmy0gO8kAgRsokV49lP//aAAwDAQACAAMAAAAQj8//xAAZEQEAAwEBAAAAAAAAAAAAAAABESExAMH/2gAIAQMBAT8QIYiiTWOGQWMVOc5tU5TXrv/EABwRAAICAgMAAAAAAAAAAAAAAAERACExQXGB8P/aAAgBAgEBPxDaWEsUpqMJY0EQ+xVlPE/euJ//xAAYEAEBAQEBAAAAAAAAAAAAAAABESEAQf/aAAgBAQABPxAkbGPKyoR9huOjyDIVLbzfcPFrqoKKqUIAIERBERDl6aF+CtQqVDATtIi38fc5kZQJUBEwSc06KmZA9vf/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;lsp&quot;
        title=&quot;&quot;
        src=&quot;/static/11251966a20a6a13bd66765e32f3618b/672e7/lsp.jpg&quot;
        srcset=&quot;/static/11251966a20a6a13bd66765e32f3618b/953fe/lsp.jpg 500w,
/static/11251966a20a6a13bd66765e32f3618b/672e7/lsp.jpg 787w&quot;
        sizes=&quot;(max-width: 787px) 100vw, 787px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Consider the case of a Rectangle class with a &lt;code class=&quot;language-text&quot;&gt;SetWidth&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;SetHeight&lt;/code&gt; method, and a Square class that extends Rectangle. Since a square has equal sides, we might be tempted to make the &lt;code class=&quot;language-text&quot;&gt;SetWidth&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;SetHeight&lt;/code&gt; methods override each other to ensure that the sides are always equal. However, doing so violates the LSP, because a square is not a rectangle in the traditional sense, and it doesn’t follow the contract of the Rectangle class.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 801px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a1042cbc4a0fe985398fc27289402ca9/8eeff/lsp-shapes.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 27.400000000000002%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAFABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAYI/8QAFwEAAwEAAAAAAAAAAAAAAAAABQYHCP/aAAwDAQACEAMQAAABq6w09Cc9BiC//8QAGhAAAgIDAAAAAAAAAAAAAAAAAQIDBwQSJ//aAAgBAQABBQLGm6RbzaWDASw//8QAIhEAAQIDCQAAAAAAAAAAAAAAAQIhAAMFBAYRMVRhkbHx/9oACAEDAQE/AVkmiVLa8EjBhpbbyXzLwh0jzqP/xAAjEQABAQcEAwAAAAAAAAAAAAABIQACAwUGETEEFFFhIkFx/9oACAECAQE/AYToFSycL5UnqSVOd7KsG9wOhYdNER94ccqcD2VP0t//xAAnEAABAgQFAwUAAAAAAAAAAAACAQMREhMhAAUWIjEEIzMlMkFhkf/aAAgBAQAGPwJpqXdrzy1X5oahXbJUowhbx8YzmIo4i9PlMEMnRl9PYW1J1vni8bfd8GQ9tFP2CTiomwPk3DL9LH//xAAdEAACAQQDAAAAAAAAAAAAAAABIQARMUFhUXGh/9oACAEBAAE/Ibst3F9Ykezg0/NKgo4U+wKSwobw/Cmt2T//2gAMAwEAAgADAAAAEI//AP/EABkRAQEBAQEBAAAAAAAAAAAAAAERITEAQf/aAAgBAwEBPxBzYpahgVJIKgrqqEIt6lZi34QBhAAIQz3/xAAZEQEBAAMBAAAAAAAAAAAAAAABEQAhMUH/2gAIAQIBAT8QO0EVemfQuOJQApjROICDR0BTRUVdquf/xAAXEAEBAQEAAAAAAAAAAAAAAAABESEA/9oACAEBAAE/ELOtCmDAUo1tHrJ1VJBGhLS2xhI90ZWJxAJaAVlVCEO//9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;lsp shapes&quot;
        title=&quot;&quot;
        src=&quot;/static/a1042cbc4a0fe985398fc27289402ca9/8eeff/lsp-shapes.jpg&quot;
        srcset=&quot;/static/a1042cbc4a0fe985398fc27289402ca9/953fe/lsp-shapes.jpg 500w,
/static/a1042cbc4a0fe985398fc27289402ca9/8eeff/lsp-shapes.jpg 801w&quot;
        sizes=&quot;(max-width: 801px) 100vw, 801px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// this unit test would fail&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;rectangle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Rectangle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;50&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;rectangle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SetWidth&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;rect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;rectangle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Height&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 785px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c2622a7e0b7b689e465ae72e931bb4cb/775d5/lsp-shapes-table.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 19.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAEABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAQGCf/EABcBAAMBAAAAAAAAAAAAAAAAAAIDBAb/2gAMAwEAAhADEAAAAcf6oaeGIGH/AP/EABkQAAIDAQAAAAAAAAAAAAAAAAQhAgURE//aAAgBAQABBQK4ii96kMj/xAAeEQAABAcAAAAAAAAAAAAAAAAAAQIDBDIzcnOxsv/aAAgBAwEBPwE67WF/uHCJEWp0P//EAB0RAAECBwAAAAAAAAAAAAAAAAIAAQMRMnFyscL/2gAIAQIBAT8BF3mOMTlDSNm0v//EACMQAAEDAwIHAAAAAAAAAAAAAAECERIAAyEiQQQTNFFSYmT/2gAIAQEABj8CkFEaoFgjLSYlUeY+POPrSNSum4Df5LFXy5D3rpYFgHWcAdhtX//EABsQAQEBAAIDAAAAAAAAAAAAAAERIQBBMWHh/9oACAEBAAE/IZ6FICaaMJAACmHnojG59u+N82Y1T1MpB0Q5/9oADAMBAAIAAwAAABCL3//EABgRAAIDAAAAAAAAAAAAAAAAAAAxQVHw/9oACAEDAQE/EFoB0qn/xAAYEQEAAwEAAAAAAAAAAAAAAAABADFRcf/aAAgBAgEBPxCwPRyE2PZxP//EABsQAQEAAgMBAAAAAAAAAAAAAAERADEhQVGh/9oACAEBAAE/EGdiLwu3Vnap8AFe17aO0ul0SnmfbmV2cMrGjLn/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;lsp shapes table&quot;
        title=&quot;&quot;
        src=&quot;/static/c2622a7e0b7b689e465ae72e931bb4cb/775d5/lsp-shapes-table.jpg&quot;
        srcset=&quot;/static/c2622a7e0b7b689e465ae72e931bb4cb/953fe/lsp-shapes-table.jpg 500w,
/static/c2622a7e0b7b689e465ae72e931bb4cb/775d5/lsp-shapes-table.jpg 785w&quot;
        sizes=&quot;(max-width: 785px) 100vw, 785px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;To adhere to the LSP in this case, we could create separate Square and Rectangle classes, each with its own &lt;code class=&quot;language-text&quot;&gt;SetWidth&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;SetHeight&lt;/code&gt; methods. Alternatively, we could introduce an abstract Shape class or interface that defines the common properties and behaviours of both Rectangle and Square and then have separate implementations for each.&lt;/p&gt;
&lt;p&gt;The key takeaway here is that the Liskov Substitution Principle is not just about substituting objects of a superclass with objects of its subclasses; it’s also about ensuring that the subclasses follow the same contract as the superclass, without introducing impure inheritance hierarchies. By following this principle, we can ensure that our software systems are modular, flexible, and maintainable.&lt;/p&gt;
&lt;h2&gt;Interface Segregation Principle&lt;/h2&gt;
&lt;p&gt;The Interface Segregation Principle (ISP) advises software designers to avoid depending on things that they don’t use. The principle emphasizes the importance of creating simple and focused interfaces that are easier to understand, use, test, and validate.&lt;/p&gt;
&lt;p&gt;The ISP states that clients should not be forced to depend on interfaces they do not use. In other words, an interface should only include methods that are relevant to the client. This principle helps to avoid bloated interfaces that carry unnecessary baggage and can cause problems later on.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8aed51fd5f72b7f0f6b5cb25896f4721/c4e52/john-barkiple-l090uFWoPaI-unsplash.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.60000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAANABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABgACB//EABQBAQAAAAAAAAAAAAAAAAAAAAX/2gAMAwEAAhADEAAAAXYwm6Gc5dagXP/EABsQAAMAAgMAAAAAAAAAAAAAAAIEBQMGABIT/9oACAEBAAEFAraqr/AmEylRmljyalsTxW3PHriptEX/xAAfEQADAAICAgMAAAAAAAAAAAABAgMEEgURExQiMVL/2gAIAQMBAT8B4y8870OPEJJh1y4xrkTOSLp5wPgkKZLQBfISZaqrrj6CkoWqsnnGXJylOey10RV8jks76gDZ2bIBZ/2T9t2e272P/8QAHxEAAgMBAAEFAAAAAAAAAAAAAQMCBBIRBQATFCEy/9oACAECAQE/AfM3JU6D7bH7V1cq8ZI2yFi0xaAWMDY7ABEExhFMvdIFiz8eUpLZd8fuXa6lknRhK5dhIa4fuKaD1gn9HLmd70y131//xAAlEAADAQABAwQBBQAAAAAAAAACAwQBEgUREwAGFCIVJDJBUnH/2gAIAQEABj8Cqr6Kc35eOeOTqAiv5di02XjxX+RVVOxKVJXSv4xTsLWuFzQ0tA/QoauSfGG6i6Ek0VNlN1VTF0OydILJnjZnMdYgFmwmaTD3gE4ye3x6t+jnKi21NznnSY6TB3V0AsBAdARUscWvPqH17b6pkHiCJOte2lL4ivKGTUL6gxqq7sXl92tXN4H7XU1LRPv4B3lzvjEG+J1Tl/ehp8CN7x8uDnAeQ537ccHPt/XuO04Tnn4aWzjpuIt4I7KH+Mwc7D+0cwc/3vu//8QAGRABAQEBAQEAAAAAAAAAAAAAAREAITFB/9oACAEBAAE/ITzgMr2xsrUJiVixG/QCxKivBYxOKxNytyUoWz5lQou3Al+whgLzE4uedZW4e3WZynPCaXzxe/8A/9oADAMBAAIAAwAAABA0/wD/xAAYEQEBAAMAAAAAAAAAAAAAAAABABEhMf/aAAgBAwEBPxAYWOdoETt5qsaST27CBzGkpNR//8QAFhEBAQEAAAAAAAAAAAAAAAAAAREA/9oACAECAQE/EF9ACay5blyDi0bZQ6lbs2gVJA//xAAYEAEBAQEBAAAAAAAAAAAAAAABABEhMf/aAAgBAQABPxA45C+tQgodec39wwv0jDcRTukMdOxSVpOpv2cfZ3GYAJimzKtUTg259dlPBPLKQO9SasX/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;john barkiple l090uFWoPaI unsplash&quot;
        title=&quot;&quot;
        src=&quot;/static/8aed51fd5f72b7f0f6b5cb25896f4721/451a4/john-barkiple-l090uFWoPaI-unsplash.jpg&quot;
        srcset=&quot;/static/8aed51fd5f72b7f0f6b5cb25896f4721/953fe/john-barkiple-l090uFWoPaI-unsplash.jpg 500w,
/static/8aed51fd5f72b7f0f6b5cb25896f4721/0a251/john-barkiple-l090uFWoPaI-unsplash.jpg 1000w,
/static/8aed51fd5f72b7f0f6b5cb25896f4721/451a4/john-barkiple-l090uFWoPaI-unsplash.jpg 2000w,
/static/8aed51fd5f72b7f0f6b5cb25896f4721/c7e40/john-barkiple-l090uFWoPaI-unsplash.jpg 3000w,
/static/8aed51fd5f72b7f0f6b5cb25896f4721/120d2/john-barkiple-l090uFWoPaI-unsplash.jpg 4000w,
/static/8aed51fd5f72b7f0f6b5cb25896f4721/c4e52/john-barkiple-l090uFWoPaI-unsplash.jpg 5184w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;©️ Photo by &lt;a href=&quot;https://unsplash.com/@barkiple?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;John Barkiple&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/l090uFWoPaI?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Suppose we have a Customer Operations class that has information about deliveries and payments. We also have two reporting services, a Delivery Reporting Service that consumes information about deliveries, and a Billing Reporting Service that consumes information about payments. The Customer Operations class has a method that returns all the information, and both reporting services depend on this method.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1040px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a33a511317441b1c0247b27d923b5574/71458/isp-violation.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 52%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAKABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAUJB//EABUBAQEAAAAAAAAAAAAAAAAAAAYH/9oADAMBAAIQAxAAAAGvzlfNyhjaWG1g5J//xAAbEAABBAMAAAAAAAAAAAAAAAAGAQIDBwAFFv/aAAgBAQABBQKUEBtdmw4ktWKvA6Ntloig1YMb3ef/xAAiEQABAwMDBQAAAAAAAAAAAAAFAQIEAAMSERMhIiNFlNL/2gAIAQMBAT8BJEI4spCD2RcFY5NYu/2mMRd2U6z1W2swuYaZNz15pBg1PHwvVsfFf//EACERAAIBAwMFAAAAAAAAAAAAAAEFBAIDEwAREiIjQXTT/9oACAECAQE/AUymW6SsX992zplJhOMXv3LhGCDRJPC9XcyWspPCvGR0jzouG5O5aMSfek/XX//EACgQAAEDAgQEBwAAAAAAAAAAAAECAwQFEQASEyIhJDFBBhAjNFFVdP/aAAgBAQAGPwI1KRT2YiIrjcpUqRUp7bTLiXgtDi1OzNMDVy8FbSbJtxtiNTpk2lVZxDq3YsVmq+qXdJYWUIiSW3HLNZ7p3AAFVuF8WRRkDNuPOVDrYDvL+AMeIrgHk2+v64+KFtT7iodh9XK8v//EABwQAQEAAgIDAAAAAAAAAAAAAAEhABExcUFRYf/aAAgBAQABPyFMmULINNOtRGCHEWgqMwDaGstKai3tvaeFokwzAQQDPvgWCTWm4pJ7vdw4OjP/2gAMAwEAAgADAAAAEIAP/8QAGhEBAAIDAQAAAAAAAAAAAAAAAREhADFRkf/aAAgBAwEBPxAhGLqD6W1kGxG8AAEOGeHd5//EABoRAQACAwEAAAAAAAAAAAAAAAEhQQARMWH/2gAIAQIBAT8QBs6Q/wAnecFumKkzqqtdUwQeZ//EABkQAQADAQEAAAAAAAAAAAAAAAEAESExwf/aAAgBAQABPxA8GESTpcsihmanGkJpXFdiqL8FSa5FJdkHQLVSxphUKCBEHacvewoA4MAogICQCAkarMmc8Cf/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;isp violation&quot;
        title=&quot;&quot;
        src=&quot;/static/a33a511317441b1c0247b27d923b5574/71458/isp-violation.jpg&quot;
        srcset=&quot;/static/a33a511317441b1c0247b27d923b5574/953fe/isp-violation.jpg 500w,
/static/a33a511317441b1c0247b27d923b5574/0a251/isp-violation.jpg 1000w,
/static/a33a511317441b1c0247b27d923b5574/71458/isp-violation.jpg 1040w&quot;
        sizes=&quot;(max-width: 1040px) 100vw, 1040px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In this scenario, we have violated the ISP because the reporting services depend on an interface (i.e., the Customer Operations class) that carries baggage they don’t use. This means that if we make changes to the Customer Operations class, it can affect the reporting services, even if the changes are unrelated to deliveries or payments.&lt;/p&gt;
&lt;p&gt;To fix this, we can introduce two interfaces, IDeliveries and IPayments, that contain only the relevant methods for each reporting service. The Customer Operations class can then implement both interfaces and provide the necessary information to the reporting services via these interfaces.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 896px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b5c3b9b0756732909d79e88aff995c35/fd39b/isp-violation-fix.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 69.19999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAOABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAYICf/EABYBAQEBAAAAAAAAAAAAAAAAAAQGB//aAAwDAQACEAMQAAABt2n2mUtDjEk03BK//8QAHBAAAgICAwAAAAAAAAAAAAAABQYBBwMEAhEh/9oACAEBAAEFAtYjWHA1Ysg8IbCSr/p1L7oBaS7KaDzNEef/xAAjEQABAwMCBwAAAAAAAAAAAAADAQIEBRETAAYSFCI0QZXS/9oACAEDAQE/ASkiU0j6NIJH5iqYMCgo4GR2ZTPCLOLO5h7Ebfrtwol/Ok26RE7ineihfev/xAAkEQACAQIDCQAAAAAAAAAAAAABAwQFFAIGEQASISMyNFFjlv/aAAgBAgEBPwFCp9ZUvMUVUy0olzdCVmCS2WwIjrkPEV1tgZF1Ti05e8cZOh6eJzaontav9PUT49e3/8QAJhAAAgIBAwMDBQAAAAAAAAAAAQIDBAUAERIGEyMUISIVMUJRcf/aAAgBAQAGPwKCpF0/1StxMxFSilabIGBbseQ9OkjcssQa4nAk3KMDD7lPx1Ws53E5PMV4sjDHFWxclhLCTWI5o+83p54CYUQMH5FgOQIXfTgdD9YDi+x82RIJ4Id1P1H7e+39B1k8tjlrtbqrV7Qsqzw+W5BA/NUKsfHK3HZh8ttY3E348StO1JbSY14J0m8NKxYTts0zKPnGnLcH25fsba//xAAbEAEBAAMAAwAAAAAAAAAAAAABEQAhMUFRYf/aAAgBAQABPyEVQQUtNq28XMxCuKnHbyUqIRPscWIQbA4MjzDW46UMRoKNBGOuBVdrGXbSIpiAvfi+d5//2gAMAwEAAgADAAAAEMcv/8QAGhEBAQACAwAAAAAAAAAAAAAAAREhQQAxUf/aAAgBAwEBPxBeki2jLUMAwKyBDp8KZGQZgxdoPP/EABoRAQEBAAMBAAAAAAAAAAAAAAERIQAxQVH/2gAIAQIBAT8QEkZlwI4MtYIODhJZ2jALUuop8IeCf//EABgQAQEBAQEAAAAAAAAAAAAAAAERIQAx/9oACAEBAAE/EJ+p/wCJWKZCuUJQGWE5LDKdRoDTaMQxroEYKKgmpYRh7wwZ+yGvN+tQQgnPcBIJ9LjqcVuWd//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;isp violation fix&quot;
        title=&quot;&quot;
        src=&quot;/static/b5c3b9b0756732909d79e88aff995c35/fd39b/isp-violation-fix.jpg&quot;
        srcset=&quot;/static/b5c3b9b0756732909d79e88aff995c35/953fe/isp-violation-fix.jpg 500w,
/static/b5c3b9b0756732909d79e88aff995c35/fd39b/isp-violation-fix.jpg 896w&quot;
        sizes=&quot;(max-width: 896px) 100vw, 896px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;By doing this, we have eliminated the unnecessary dependencies between the reporting services and the Customer Operations class. The Delivery Reporting Service only depends on the IDeliveries interface, and the Billing Reporting Service only depends on the IPayments interface. This makes the interfaces simple, focused, and relevant to the client, and it also makes the reporting services easier to test and validate.&lt;/p&gt;
&lt;p&gt;By creating focused interfaces, we can improve the modularity and flexibility of the system. We can also make the system easier to test and validate since we only need to test the relevant methods. Additionally, focused interfaces can simplify the implementation of the client code since they only need to implement the necessary methods.&lt;/p&gt;
&lt;p&gt;Acknowledge this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interfaces that are simple and focused are easier to understand and consume&lt;/li&gt;
&lt;li&gt;Interfaces that are focused on a specific behaviour can be more easily tested&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Dependency Inversion Principle&lt;/h2&gt;
&lt;p&gt;The Dependency Inversion Principle (DIP) states that high-level modules should not depend on low-level modules, but both should depend on abstractions. This means that the policy (i.e., high-level module) should not depend on the details (i.e., low-level module), but rather the details should depend on the policy.&lt;/p&gt;
&lt;p&gt;To adhere to the DIP, we need to program abstractions rather than concretions. This means that we should avoid depending on concrete classes and instead depend on abstractions or interfaces. By doing this, we can make our systems more flexible and maintainable since we can change the implementation of the low-level details without affecting the high-level policies.&lt;/p&gt;
&lt;p&gt;The key takeaway from the DIP is that we should program to the interfaces or abstractions, not the implementations. This approach enables us to decouple the modules in our system and create a more flexible and maintainable architecture.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b88c941bafaeba56f76a92a509a42650/440e5/dmitriy-zub-jibUsRaauLY-unsplash.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 68.39999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAOABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAgEBQf/xAAUAQEAAAAAAAAAAAAAAAAAAAAF/9oADAMBAAIQAxAAAAF66bGIIybti3CZf//EABsQAAICAwEAAAAAAAAAAAAAAAMEBQYBAgcT/9oACAEBAAEFArFNO+grkJB0bYjaCqUaF/POKqYi0ImkL//EACERAAICAgEEAwAAAAAAAAAAAAEDAhEEExIABSEiIyRh/9oACAEDAQE/AThYU8VCOSwIqpjRifY3Snsk7YG2ZV8IVZx9EVeocJNJ7RGzxzBV+LRK6/ffr//EACERAAEEAgEFAQAAAAAAAAAAAAECAxETBBIUAAUhIjFB/9oACAECAQE/AefmIysh7VZK3BU0cmWKkorprr1CCRbZHIuU4dyyUMpT3lcDbDO0eYyExP7Hp86//8QAIhAAAwABBAMBAAMAAAAAAAAAAQIDBAUREhMAFCExIlFx/9oACAEBAAY/AvTwM7G00YkF1HVdRypPeMMXm4jiqsXSvs5PTV1WZ7DJQVBUtvg6Zq1YVpqmPi5ml5mD9llYeSxQVulel49Z63ZwmzypzE/4P4KQvG02340lRXm2x4nZlJB2II/3zNeNswY2VMRydPehpjvTgZeytKvXJTI6+K9iVXbrRlAO+8qmOoB4wnjYpGpZZ9SM/wAXFNKO2Py+9hkVL7kE7HwQxgZyUsdv7dmLO5+/WZiSx/Sfp8//xAAZEAEAAwEBAAAAAAAAAAAAAAABABEhMXH/2gAIAQEAAT8hp2RYDpUdgYMR5FN6znUHVZ9YlCS05MpwI6TRiWgv8R2EZ3Nz8kLbvWFcAYDauHNtF6IlrUVZ/9oADAMBAAIAAwAAABDA3//EABkRAQEAAwEAAAAAAAAAAAAAAAERACFRgf/aAAgBAwEBPxC574SOAh0oRVl3bDaxqiIEDAWc8f/EABgRAQEBAQEAAAAAAAAAAAAAAAERIQBR/9oACAECAQE/EAlVcAOFKtTHuIKc8JYYNErVlLB93//EABgQAQEBAQEAAAAAAAAAAAAAAAEAESEx/9oACAEBAAE/ECNP5dz8OmmspSg3quu2+AwfFxF+Uzu1DfChAXiA3ynnhkC6PXZRqOIYR+Co78w5yQ7MpDjX/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;dmitriy zub jibUsRaauLY unsplash&quot;
        title=&quot;&quot;
        src=&quot;/static/b88c941bafaeba56f76a92a509a42650/451a4/dmitriy-zub-jibUsRaauLY-unsplash.jpg&quot;
        srcset=&quot;/static/b88c941bafaeba56f76a92a509a42650/953fe/dmitriy-zub-jibUsRaauLY-unsplash.jpg 500w,
/static/b88c941bafaeba56f76a92a509a42650/0a251/dmitriy-zub-jibUsRaauLY-unsplash.jpg 1000w,
/static/b88c941bafaeba56f76a92a509a42650/451a4/dmitriy-zub-jibUsRaauLY-unsplash.jpg 2000w,
/static/b88c941bafaeba56f76a92a509a42650/c7e40/dmitriy-zub-jibUsRaauLY-unsplash.jpg 3000w,
/static/b88c941bafaeba56f76a92a509a42650/440e5/dmitriy-zub-jibUsRaauLY-unsplash.jpg 3934w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;©️ Photo by &lt;a href=&quot;https://unsplash.com/@dimitryzub?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Dmitriy Zub&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/jibUsRaauLY?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The analogy of the excavator is a good illustration of how the DIP works in practice. By depending on the abstract concept of a fixture rather than a specific fixture, the excavator can be easily adapted to different tasks without having to replace the entire machine. This approach enables us to reuse the excavator and make it more flexible and adaptable to different situations. If this were violated, imagine having to get a new excavator each time a task requires a different fixture.&lt;/p&gt;
&lt;p&gt;Suppose we have an application host, such as a console application or web application, that depends on an application core. The application core contains the business logic or policy of the system. However, the application core also depends on a CRM SDK, which is an implementation detail or infrastructure concern.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 348px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c88dd92743d5aeee210886a09a97e15b/6817d/dip-violation.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 168.67816091954023%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAiABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAcFBggE/8QAFgEBAQEAAAAAAAAAAAAAAAAABgUH/9oADAMBAAIQAxAAAAHUfDvSO1MDBDcAqvNkHaq01MOUXhEpoCiBuOYMoA9Y/8QAHRAAAgIDAQEBAAAAAAAAAAAABAUGBwACAxcBFf/aAAgBAQABBQI2vLM6F+eWVtlcR+So0ZFlQUQjS0K/11WS2OOeBtMDGF/KQG3yOV4PHg21v8FbP24fXA7kBK0lCpX1kf4yfEixbzG//8QAKhEAAQMCAwUJAAAAAAAAAAAAAQIDEQQSAAUhBiIyNEExNVFScXJ0s8H/2gAIAQMBAT8BVkezNypzwg3GQcxy6QZ1BuZumSZnXoezFC3RU9IwzT1QeZbbCW3S+24Vp8StEJV6gYdTsUHFhzjC1BfevGlUGLd3iBi3d8uGMw2aaaQ2y+2lpIhAIq5Anrem+ZOt2uK7naz5VR9q8UnLte39GP/EACoRAAEEAQMCAwkAAAAAAAAAAAECAwQREgAFBiEiBxMxJTM0NVJydLTB/9oACAECAQE/AW+TczwRjxlKk4pxI2jeKUnEURhJCaICSMRj1JHqb3N7cpU+VIlwVR5LzpW8ymK+yG1kDtDThK0eg6KJOmFeI5ZbUz7tTaFNn2FflqQCLz77KCknPu+rrepW1cxekOOyYzq31m3FBUGiaFV5Sw3VVWHTW1/Ldu/BifrtanfFv/f/AAa//8QAMRAAAgIABQEEBwkAAAAAAAAAAgMBBAAFERIhIgYTFkEUMTIzYXGCNUJRUmN2lLHT/9oACAEBAAY/Ar5rGwwHZlaehvjCwjSqy0xi1RXFuwdVTEfiv1RHGNy675H982zjjgtJho+cfTOsfK1U7QEc3GZtZsq35mWYyNQ69MFD6QRlPBrb0eXtadeH1bHaXLlWKzmV3qKXbluScrastEzyBjIz8YxEeKMs8/VL/OZ/QwdnK82q3ULcSDamWbRcILYS+pY8wDVl9UYuWvEuZpi5etXu5GjlhiorVhtggE2JlhAJOLbuKfzaa4gp7UZvGwy01oZT93cvXhPqkddBniIn2dcPqDmty739wrZOciqookq9avsgUCIbYGsM66a6lOuMyy6OzOb24y2++gdpNiiKWsQcLmQhhwcbpnpEurER4SzvqPSNbOXR1s3FA+84medIn+8MI8gzOsS2d3K2vpyXu1tgugpjSYZ8+MZ4xuW0GMPM7RGbKdczMpPkiIlzJTPnM84+yst/g1f8sNgMvohHpEzoNRAxr3KOeF/DH//EABwQAQEBAAMBAQEAAAAAAAAAAAERIQAxUWFBgf/aAAgBAQABPyEdouBiEreoTMnhGiw7x+9rXvAucACoYMwEH2lWTqYZV/OAZVU6FN5JPKkWrx7r7xmhEDIKLBBJtaBObKMNubqx12l8GPZfPl2zogCNoSyKMpsRehB4IwGgcBIoSNkFBk5l3E1SRZDkdFoBqE3MICAulQpz7MFuADFNX682/n8nvhb5cqQUEWAvcA/Of//aAAwDAQACAAMAAAAQtCMAi8//xAAaEQEBAAMBAQAAAAAAAAAAAAABEQAhQRCh/9oACAEDAQE/EAcvnm0SwBVEFZAr9m4LCmKpEclMD8DoYGgt4BV6VSYxoTUDYTKpSU2+AvhZf//EABkRAQEBAQEBAAAAAAAAAAAAAAERACEQMf/aAAgBAgEBPxCikG8oq4wkEU2FIAQwQEBPtKrd1UZIGnmCKSSsCGPRMpi0AOMAmQ9l5//EABsQAQEBAQEBAQEAAAAAAAAAAAERACExYVGh/9oACAEBAAE/EA/gu8oRqhBDBR8WqdaSGeViomAlbiDKJ2UhkHAklgHglMV8qCrXOSEFScmeAWlfVAtEEKYPkWR4Csl0zi2YNQ4mDxy+hRnl+5FaYl3E03gRfolQs5cEdOK9Vtt59jbmuEGXawWg32pL8jIU9isAb+p7ck+tw0zd+x8Bx8sKeMLlh73w1JNtilmAP//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;dip violation&quot;
        title=&quot;&quot;
        src=&quot;/static/c88dd92743d5aeee210886a09a97e15b/6817d/dip-violation.jpg&quot;
        srcset=&quot;/static/c88dd92743d5aeee210886a09a97e15b/6817d/dip-violation.jpg 348w&quot;
        sizes=&quot;(max-width: 348px) 100vw, 348px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In this scenario, we have violated the DIP because the application core depends on the details of the CRM SDK. This makes the system less flexible and harder to maintain since any changes to the CRM SDK could affect the application core and the application host.&lt;/p&gt;
&lt;p&gt;To fix this, we can introduce an interface, such as &lt;code class=&quot;language-text&quot;&gt;ICustomerLeadsRepo&lt;/code&gt;, that defines the methods for creating, updating, and adding notes to customer leads. The application host can own or define this interface since it needs to interact with the CRM SDK. The application core can then depend on this interface instead of the CRM SDK directly.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 955px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/dcc4b07fcceed81d0a9182f9fe92071d/cb61f/dip-violation-fix.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 62.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAANABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAACAkA/8QAFQEBAQAAAAAAAAAAAAAAAAAABgf/2gAMAwEAAhADEAAAAaJKKO1zaGMP+QWJIv/EAB0QAAEEAgMAAAAAAAAAAAAAAAMCBAUGAQcQERb/2gAIAQEAAQUChAakRL2CxNq6MOxY4yac3z6nrj//xAAlEQABAwIDCQAAAAAAAAAAAAACAQMEBREAIiMGExQhMTJBYcT/2gAIAQMBAT8B2XmOVGDN3MaFTTF9sQWLH010wJSNsncxWyd42687YSPUfNQbX3wKJ9GP/8QAIhEAAQQBAgcAAAAAAAAAAAAAAQIDBAUREiEABhQVI1Gh/9oACAECAQE/Aedq9mpsq0SJllcNLjOrWmdL8oAdWhKG3ksDQnVh0jQrJyNs7GVU52qXgPXclH70nH//xAAqEAABAwEGAwkAAAAAAAAAAAABAgMFBAAREiEiMQYyQRATFCNCUVOh0f/aAAgBAQAGPwKLMXMVDkimtpjHNqkJtYcqipIYSpDqA2sKWoDC7oN+rK1MuooZeu8UtxtAiaFyuU2W0hRLwQtPdpOK5B9RBHSxUILi1Nxw64B8HYH5DlnbhDzOSaiSdPOQ63nvkfbe6/rbc/X52f/EAB0QAQEAAgEFAAAAAAAAAAAAAAERACEQQVFhcZH/2gAIAQEAAT8hZc2U6LIJSQ2YUGhDr2dCVijZwARULkqDdBj1RxTWRp3CeJtpQThye/rn/9oADAMBAAIAAwAAABDf3//EABkRAQEBAQEBAAAAAAAAAAAAAAERITFRwf/aAAgBAwEBPxBAT0+i/ZNDgQEBAAsdFXNlznv2/wD/xAAZEQEAAwEBAAAAAAAAAAAAAAABABEhMVH/2gAIAQIBAT8QBw+tvca9F6MjU3bEwMxovnh1n//EABsQAQEAAgMBAAAAAAAAAAAAAAERITEAQVHB/9oACAEBAAE/EI1NnbCOmqnGF/ltHc5jIuKZW027VPZBUghAUJw/MqiXFa0mE0UkcgjEW70M/ejgQAYADfAmc7995//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;dip violation fix&quot;
        title=&quot;&quot;
        src=&quot;/static/dcc4b07fcceed81d0a9182f9fe92071d/cb61f/dip-violation-fix.jpg&quot;
        srcset=&quot;/static/dcc4b07fcceed81d0a9182f9fe92071d/953fe/dip-violation-fix.jpg 500w,
/static/dcc4b07fcceed81d0a9182f9fe92071d/cb61f/dip-violation-fix.jpg 955w&quot;
        sizes=&quot;(max-width: 955px) 100vw, 955px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;By doing this, we have inverted the dependency and made the system more flexible and maintainable. The application host can now provide the necessary details to the application core via the ICustomerLeadsRepo interface, and the CRM SDK can implement this interface without affecting the application core or the application host.&lt;/p&gt;
&lt;p&gt;In summary, the DIP is about inverting the dependency between high-level policies and low-level details by programming to abstractions rather than concretions. By doing this, we can create a more flexible and maintainable system that can adapt to changes in the implementation details without affecting the high-level policies.&lt;/p&gt;
&lt;h2&gt;Component Principles&lt;/h2&gt;
&lt;p&gt;Now that we have covered the SOLID principles that operate at the module level, let us move a level higher, to components.&lt;/p&gt;
&lt;p&gt;The SOLID principles operate at the module level, while the principles of component design operate at a higher level of abstraction. Three principles of component design are important:&lt;/p&gt;
&lt;p&gt;Reuse/Release Equivalence Principle: This principle states that classes and modules that are grouped into a component should be releasable together. This means that if you want to reuse a particular component in another project, you should be able to release that component without having to release any other unrelated components.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Common Closure Principle: This principle states that we should group those classes that change for the same reasons and at the same time. In other words, we should create components that have high cohesion and low coupling. This principle is similar to the Single Responsibility Principle but operates at the component level.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Common Reuse Principle: This principle states that we should not force users of a component to depend on things they don’t need. This means that we should create components that are highly cohesive and loosely coupled so that users can easily reuse specific parts of the component without having to depend on other unrelated parts.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Reuse/Release Equivalence Principle and the Common Closure Principle are inclusive principles, while the Common Reuse Principle is not. Together, these principles help to create components that are easy to understand, easy to modify, and easy to reuse.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/fb746647de70ad4bb9bd1823b4afabe1/a22ce/component-principles.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 82.60000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAARABQDASIAAhEBAxEB/8QAGQABAAIDAAAAAAAAAAAAAAAAAAcIBQYJ/8QAGAEAAgMAAAAAAAAAAAAAAAAAAwUAAgb/2gAMAwEAAhADEAAAAemslSbCbhTpa6Asx9YwlLWDPOf/xAAcEAACAgIDAAAAAAAAAAAAAAAEBgUHAAIBNDb/2gAIAQEAAQUCr1UZVPjQkprWlBCb4eLmy9IuNrhrGbgsK61P+Wz/xAAmEQACAgECAwkAAAAAAAAAAAACAwEEBRETEiEjAAYQNUFhcXSx/9oACAEDAQE/Aa44vHJV3fg3bttbiRxscTNrqHZ6ghoJc5lU7i9BidII9CBGGpV0rSE2uFYwI63bcco9gcAR8CIjHpEdrHnmM+nkv2l4f//EACMRAAICAQMDBQAAAAAAAAAAAAIDAQQFERIxAAYTEDZidbL/2gAIAQIBAT8BuRn8xfPvDeoKmPNAXUpr1RrlZ0SqnMrM5ZIRtDyiKmbykdxgveDbPcWRt2G2WRR8jjky0x1Eo1n5NQxk8cmZlPJFM9U/bea+ww/5v+n/xAAoEAACAgIABAQHAAAAAAAAAAACAwEEBRIAERMiBhAUIRUjMnN1sbP/2gAIAQEABj8C8ROz+TXaBq4YisrIXLIMbXhrG32teAGhrxkBPWDYQ97pmRDjNLx9gcbYsVmUquQrX22gC0yuMzqY/MX05MQlod+rOouNh4ZWseJzxxHca8KdNjMghQEtAez7IoKCYazYSwXC4k9ucsJk8X8sajeFClZstQv63rQo2SsefbBFy13LtESIi9h9sh08TGJ+HWlQSU2fV1XRaWRgQN0XO4wvRqZGIiOmwOa2xHlY+w7+ZcP/ADOQ/a/L/8QAGhABAQACAwAAAAAAAAAAAAAAAREAQSAhMf/aAAgBAQABPyEG2pmGbVfu12zdfDwogcinCM25xxL0YLRDnfZm/bTEWCxg4iHlK5oFXIugJw5jP//aAAwDAQACAAMAAAAQbA8A/8QAGREBAQADAQAAAAAAAAAAAAAAAREAECEx/9oACAEDAQE/EE/g13dACvMVZkdMckWDW4I+sQQG4/8A/8QAGBEBAQEBAQAAAAAAAAAAAAAAAREhABD/2gAIAQIBAT8QfzP4pXVJB59xSgGIlhCY3oolfGP/xAAYEAEBAQEBAAAAAAAAAAAAAAABABEgIf/aAAgBAQABPxBnPyOp8P7bM8wPWWJOeNMRMgNA0jF81mJy4UysBADwZQdmo7cg05LidN6aui7/AP/Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;component principles&quot;
        title=&quot;&quot;
        src=&quot;/static/fb746647de70ad4bb9bd1823b4afabe1/a22ce/component-principles.jpg&quot;
        srcset=&quot;/static/fb746647de70ad4bb9bd1823b4afabe1/953fe/component-principles.jpg 500w,
/static/fb746647de70ad4bb9bd1823b4afabe1/a22ce/component-principles.jpg 680w&quot;
        sizes=&quot;(max-width: 680px) 100vw, 680px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The three principles of component design create a tension between the need for reuse, the need for maintainability, and the need to avoid forcing users to depend on things they don’t need. The optimal position in this tension triangle will depend on the current concerns of the development team and the project’s current stage of development.&lt;/p&gt;
&lt;p&gt;Early in the development of a project, the focus is often on developability, so the Common Closure Principle (CCP) is more important than the Reuse/Release Equivalence Principle (REP) or the Common Reuse Principle (CRP). As the project matures, the focus may shift towards reuse, and the team may prioritize the REP and CRP over the CCP.&lt;/p&gt;
&lt;p&gt;Ultimately, the value of these principles lies in their ability to create components that are easy to understand, easy to modify, and easy to reuse. By following these principles, developers can create software systems that are flexible and adaptable to changing requirements and can be easily maintained over time.&lt;/p&gt;
&lt;h2&gt;Stable Dependencies Principle&lt;/h2&gt;
&lt;p&gt;Stability in software components refers to how difficult it is to make changes to that component without affecting other parts of the system. A stable component is less likely to change, and thus less likely to cause cascading changes throughout the system.&lt;/p&gt;
&lt;p&gt;It is generally better to depend on stable components than on unstable ones. If a component is unstable, it may change frequently and cause cascading changes in dependent components, leading to more maintenance work and potential issues. On the other hand, stable components are less likely to change frequently and can provide a more reliable foundation for the software system.&lt;/p&gt;
&lt;p&gt;The formula for calculating stability is&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;I = Fan-out / (Fan-out + Fan-in)&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;where Fan-out refers to the number of outgoing dependencies and Fan-in refers to the number of incoming dependencies.&lt;/p&gt;
&lt;p&gt;Modules with a high value of I (close to 1) have many outgoing dependencies and few incoming dependencies, making them more unstable and easier to change. On the other hand, modules with a low value of I (close to 0) have few outgoing dependencies and many incoming dependencies, making them more stable and harder to change.&lt;/p&gt;
&lt;p&gt;Software stability refers to the difficulty of making changes to a component. This can be affected by factors such as size, complexity, and clarity. One way to make a component hard to change is to have many other components depending on it. Such a component with many incoming dependencies is considered stable because any changes made to it would require a lot of work to reconcile with all the dependent components. The key rule to follow is to depend in the direction of stability, meaning that components with more incoming dependencies should be depended on by components with fewer incoming dependencies.&lt;/p&gt;
&lt;p&gt;The key takeaway is to depend on more stable components, as they are less likely to change and cause ripple effects throughout the system.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 648px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/259d1c554c34a53f9e0f4a44e65dc6c6/4ed6c/stability.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 88.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAASABQDASIAAhEBAxEB/8QAGgABAAIDAQAAAAAAAAAAAAAAAAYJBAUHCP/EABgBAAIDAAAAAAAAAAAAAAAAAAMGBQcI/9oADAMBAAIQAxAAAAG1uDer+fty5v0xLk1TlgGkqUioID//xAAcEAACAgMBAQAAAAAAAAAAAAAFBgIEAQMHFBb/2gAIAQEAAQUC1IairBk8Pz48HW1UUsD7OzF6qsUCY3Gu/UlHlUI4J8/hD5Zb1a/H/8QAJhEAAgIAAwcFAAAAAAAAAAAAAgMBBAAFEgYTFCEzNFFhcnO0wf/aAAgBAwEBPwE8urBcpLRQp8EKLaWTFWrMADQbvFiZXFsAGyydYrqPg9ZwchBSQJCshQKSKlqAYEFhpERjxAxyiPSMUelkvw7TfSZin2yfb+4//8QAJBEAAgIBAwIHAAAAAAAAAAAAAgMBBAUABiETFSIzNHJ0tcL/2gAIAQIBAT8BDL3WY/Its5XIdyKzQsJGbl2JaxDK/SaShx7ksYgVDKjbfqkErCViwgEDsNu2XMfYN7ntOSY1kmRmXHiIi5meI5nWU87cnydl/ZJ1kfW2Pf8Akdf/xAAtEAABAwIEBAMJAAAAAAAAAAABAgMEBREABhITFCEiMTJBYQcjJSY0QlFTVP/aAAgBAQAGPwLMavjSYM2lPM1UqqFQmPCDFDrqjF8Tjb2gqIUz1q5D8YzFQ6GqvuQpbtNcqomSKq08ChTjsLhpD1ltg7B3Qyrn4XO+FQKYJaWHZK5ixKmPy3N51pltdnHlFYTpZRZHYG58zifGhVRuLIXGkNsymSw+qGtTOlEvbKrL4dxQcsohBKdKiMT11bOZzIhaWNvcjwoggBkvB1zU067qEnUi+5pCNoab6ji4lxldxcPteR9FWxnCyUj5JzAOQH7GMe03pTzypFB6RzG5K74ke7R9Yr7U/wA8b0x//8QAGRABAQEBAQEAAAAAAAAAAAAAAREhADFh/9oACAEBAAE/IaLSs1b30WfOoOdnTAqj1GZ4IZ4l5gBkRWhc8XqRDwnoeeJ6BrzrYLyKazEtQwA4BRHUNzMjM9sj20IqKnmw8+cAgwJh4QmnxzgwHuH/2gAMAwEAAgADAAAAEEf4fP/EABoRAQEAAgMAAAAAAAAAAAAAAAERAGEQMfD/2gAIAQMBAT8QSClOAROU/ZEw52il4k0y9EFd8WvBrn//xAAbEQACAQUAAAAAAAAAAAAAAAABEQAQITFBof/aAAgBAgEBPxB4Kw+GEkR2xCU9Br6FodkGQL7p14Ev/8QAGhABAQEBAQEBAAAAAAAAAAAAAREhAEExYf/aAAgBAQABPxBg6fNNkVDtSIBhgp8lDDxASYL4fVsNZwkOuujabV6a+QsTm7Wg16bFgUpyb7gTyBpN4BCAHNrTRdasFfqo+nGVNY/Ayd3B0521IrCrOs0wC/h3/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;stability&quot;
        title=&quot;&quot;
        src=&quot;/static/259d1c554c34a53f9e0f4a44e65dc6c6/4ed6c/stability.jpg&quot;
        srcset=&quot;/static/259d1c554c34a53f9e0f4a44e65dc6c6/953fe/stability.jpg 500w,
/static/259d1c554c34a53f9e0f4a44e65dc6c6/4ed6c/stability.jpg 648w&quot;
        sizes=&quot;(max-width: 648px) 100vw, 648px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Visually looking at this we can say the first labelled component is maximally stable as it has no outgoing dependencies but has a lot of incoming dependencies. Inversely the second labelled component is unstable.&lt;/p&gt;
&lt;p&gt;We want to strike a balance between stability and changeability in our software system. If all components were highly stable, the system would become rigid and resistant to change, making it difficult to adapt to new requirements or fix issues. On the other hand, if all components were highly changeable, the system would become unstable and unreliable, making it difficult to ensure its correctness and maintainability over time.&lt;/p&gt;
&lt;p&gt;Therefore, we need to design our component structure so that some components are more stable and others are more changeable, depending on their role in the system. And we should always try to depend in the direction of stability so that changes to unstable components don’t ripple through the entire system and cause unintended consequences.&lt;/p&gt;
&lt;p&gt;The previously stable component, as shown below, is no longer stable as it now has an outgoing dependency on an unstable component. Remember our rule, always depend in the direction of stability.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 858px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e9d344ace6d50b46a9be6f3c9da3441b/4612c/stability-violation.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 64.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAcIBgn/xAAXAQADAQAAAAAAAAAAAAAAAAABAwUG/9oADAMBAAIQAxAAAAHssoKnXWgk4YpkUf/EABwQAAEFAAMAAAAAAAAAAAAAAAYBAgMEBQARIf/aAAgBAQABBQKXYIWEA/kT0CdhYeuRJ/MwYlq7CJ1z/8QAIhEAAQMDAwUAAAAAAAAAAAAAAgEDBAAFERITIhQkNZPV/9oACAEDAQE/AZlukk/GdNx+SLU0nhUxtfaAWnAhuRFd0N4yKtl1K45vHxpIEzHmrh6bV82v/8QAIxEAAQQBAQkAAAAAAAAAAAAAAgEDBAUREgAGExQhIiOE1f/aAAgBAgEBPwGDaxm40xoGo0NXa8I5CDl1me4GrUbvCsEZRx3VgxdDk0z444d2VtIGem7tSnsXv2Nv/8QALBAAAgECBAQDCQAAAAAAAAAAAQMCBAUABhESFBUhIgcQQRMWIyQyQ1GB4v/aAAgBAQAGPwJdsVlKofZ5Mp4yzDzimguKmIixr+APzBCW6pMNdZkbh24u1yXkO5W9sVXpiLo/NIrUV7Wv9pBUKCRIp+YkCa5zBFIO3GsvDV8T+PeW2H0Gv2/Q6j9Yidp+kDpP+cPvMsyZiq4OnWHlVXXRbbF8Wd8YwSFRIFJrspO74cOnXy//xAAdEAEBAAMAAgMAAAAAAAAAAAABEQAhMUFRcZGx/9oACAEBAAE/IR2N5SgOzJ5nQZco2H11N7ROFzczo6t0KRs+1xwGLTmKQY/L9wPEEciLdoPeeeGYXqqtVWq5/9oADAMBAAIAAwAAABA33//EABkRAQEAAwEAAAAAAAAAAAAAAAERMUFRcf/aAAgBAwEBPxCeAHpJatLXygAQKrCufHAd0ed//8QAGREBAAMBAQAAAAAAAAAAAAAAAQARITFB/9oACAECAQE/EE6/b4IEu0x7MkpGWwKDmFtrPVdZ/8QAGBABAQEBAQAAAAAAAAAAAAAAAREAITH/2gAIAQEAAT8QWxEZxdiebeyASACIWPYpRuGZLHMhIZKieqHDXAZPDkAViWkeizN17IkxRqJAd1U+hWSMg+qr5AIAAb//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;stability violation&quot;
        title=&quot;&quot;
        src=&quot;/static/e9d344ace6d50b46a9be6f3c9da3441b/4612c/stability-violation.jpg&quot;
        srcset=&quot;/static/e9d344ace6d50b46a9be6f3c9da3441b/953fe/stability-violation.jpg 500w,
/static/e9d344ace6d50b46a9be6f3c9da3441b/4612c/stability-violation.jpg 858w&quot;
        sizes=&quot;(max-width: 858px) 100vw, 858px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We can employ the Dependency Inversion Principle to fix this violation by introducing an abstraction in between as shown below.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 801px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/1f041c67f72556a25752abd06cc2f029/8eeff/stability-violation-fix.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75.6%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAPABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAcFBggJ/8QAFgEBAQEAAAAAAAAAAAAAAAAABAUG/9oADAMBAAIQAxAAAAHtMvmjStDDizRodP8A/8QAGxAAAwACAwAAAAAAAAAAAAAAAQUGAAQCAwf/2gAIAQEAAQUCfbFRrEItsXvBn6cRQ0S+ZToF0rTdoAGf/8QAIREAAgIBAgcAAAAAAAAAAAAAAwQBAgURFAAxM1VhZJH/2gAIAQMBAT8BaGM7ol6sVMxQyuQ2hrrxt1wTYUmBFkGL62JaOdxkm/TZXjWLRjy90yP1Lx6XH//EACARAAIDAAEEAwAAAAAAAAAAAAMEAQIFEQASFCFVgdX/2gAIAQIBAT8BzzXWzStSnYChFncmdBYTVvLcYqM9Vm7V1Uxx2Cr64GUcD9mSaniaTqr/AAeRH1p/pdf/xAAoEAABAwMDAwMFAAAAAAAAAAABAgMEBRESBhMhACMxFBUkFiI0UcX/2gAIAQEABj8CgjTlHpdUS6F+sVUao7T1Mkbe3tBEd/ezTulV8cShPnLhysjTVL2RuON136hqXr1K9qMVGVE/BSFufEV5xa+SO70ctL6YBvbjUco/z/3fpyrVFMhcaOuMypMZtLju5JcSw3ZKnGhbNX3nPhN7A+OoWvoVPeE2Zm4xJkOyW3QWEu0slcRMx2IO00ttIxUCkhw9zkccdf/EABsQAQADAAMBAAAAAAAAAAAAAAEAESExQVGR/9oACAEBAAE/IdyBc6efw9Vk1YGDDZqyhULimMzXmmAmgOVO4V4D3N55aCXSRwNhOgmA49jpAASAcAKAPAo3X6z/2gAMAwEAAgADAAAAECTf/8QAGhEBAAMAAwAAAAAAAAAAAAAAAQARQTFxgf/aAAgBAwEBPxCkCv64+9g4QggIC6a2vgmYHU//xAAaEQEBAAIDAAAAAAAAAAAAAAABEQAxQVHR/9oACAECAQE/EHmb2itZLU+UeZSoJaBA1qt47ff/xAAZEAEBAQEBAQAAAAAAAAAAAAABEQAhMUH/2gAIAQEAAT8QvIL5OWtOvgoqkFTrgRqA49gzE8syKqMNMfQ8F16AM5D33ietLTVd26uI6vmgRyqColIAVFX1VXu//9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;stability violation fix&quot;
        title=&quot;&quot;
        src=&quot;/static/1f041c67f72556a25752abd06cc2f029/8eeff/stability-violation-fix.jpg&quot;
        srcset=&quot;/static/1f041c67f72556a25752abd06cc2f029/953fe/stability-violation-fix.jpg 500w,
/static/1f041c67f72556a25752abd06cc2f029/8eeff/stability-violation-fix.jpg 801w&quot;
        sizes=&quot;(max-width: 801px) 100vw, 801px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Below is a more real-world example of respecting the dependencies rules, by ensuring that our business rules, the policy, do not depend on the details but instead the details depend on the policy.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 956px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7e7798f34dd810ef0b151eb921ee4a3b/ba672/stability-real-world.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 47.4%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAAJABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAgJBQb/xAAVAQEBAAAAAAAAAAAAAAAAAAAGB//aAAwDAQACEAMQAAABp3tdjNCnBHeHGCSH/8QAHBAAAgEFAQAAAAAAAAAAAAAABgcDAAECBTYE/9oACAEBAAEFAoluJi3q225A2DBAlhe2LE5BXd7X/8QAIREAAgIBAgcAAAAAAAAAAAAAAQQCBQMAEQYSFCUzktL/2gAIAQMBAT8BsWcVTYJ0iiCQStZ4YtxnDKTIMMdNPblyxj4gANwdDh6m2Hb1vQ/Wv//EACIRAAEEAAUFAAAAAAAAAAAAAAECAwQFAAYREiEVM2GS0v/aAAgBAgEBPwGnhP31VYZjnWlibKibkLgLbcYCUGLFExvXcwtXfUSrapPB40PODmzMZOvV5nuPnxj/xAAqEAABAwIEAgsAAAAAAAAAAAACAQMEBREABhMhEiIQFBUjMTVRUnN1tf/aAAgBAQAGPwIcyv1WstBQ3+01KRJZdZSyEpawMQOsOt94vIJKS7eK4byutef1Jcll5oIQTIcgnYaHJQUelQdERUQJSQrcaJYd7YJUqOYecyLzCPb27cMJERLCmyJb0xmb6aRigfLN/Nm9H//EABwQAQEAAgIDAAAAAAAAAAAAAAERITEAEFFx8P/aAAgBAQABPyHLAv2+GHTxJMbxRqgsQax7V9QU7L7sXWmqiCuBA+D4Okxo9HP/2gAMAwEAAgADAAAAEG8v/8QAGxEBAQABBQAAAAAAAAAAAAAAASERAEFhcYH/2gAIAQMBAT8QN4bkxM2AJxKJAoBGDscK3c3151//xAAZEQEAAwEBAAAAAAAAAAAAAAABESExAHH/2gAIAQIBAT8QQPCVY57KZTYHrJTL5hAFAoBhmd//xAAaEAEBAAIDAAAAAAAAAAAAAAABEQAQIVHw/9oACAEBAAE/EE1EgitVuOY8qW2AHzT0KaFzZIkepJCY2ZES7G7r7HRn/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;stability real world&quot;
        title=&quot;&quot;
        src=&quot;/static/7e7798f34dd810ef0b151eb921ee4a3b/ba672/stability-real-world.jpg&quot;
        srcset=&quot;/static/7e7798f34dd810ef0b151eb921ee4a3b/953fe/stability-real-world.jpg 500w,
/static/7e7798f34dd810ef0b151eb921ee4a3b/ba672/stability-real-world.jpg 956w&quot;
        sizes=&quot;(max-width: 956px) 100vw, 956px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Clean Architecture&lt;/h2&gt;
&lt;p&gt;Finally, let’s talk about Clean Architecture. Let’s jump right in with some visuals. Were are going to introduce some concentric circles that represent key areas of our software and show how Clean Architecture expects dependencies on these to work.&lt;/p&gt;
&lt;p&gt;Starting with the most stable, we would have what is critical to our operations, the entities that hold critical business rules.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 155px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ac184c2acee15e27d0b7b1663d811ed3/d8118/clean-architecture-1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAEPUlEQVR42nVV31NbVRAOZZyOIAESApVSfpVCnCb6pOUf0HH0wadKpciD+lD74jilTQItgSQkoCAFW2kSqliLLRQo5CcEKFYaIAHakQYVhs440+lY7Uxf6EPDveRz90YwVL0zm7P37O53zre7dyOTJTxGGHcd7u9PZh1A8uNoVOu8v1jVvhbUsdh/C7+/DmjYxj7syzGy/3rIKYmWJFp3ef/8taL6zkD4UNAploUuIHemkyXGevmMU2Sb+/eVI+z7d0zSDjCjMX4KGRT65cCQZs6OtInmWIrXtCn3WzYy/VaBRe6zCLzHNvbRR0aHOCbhQv8obPg44plXBs9it6fhqXLUukESy/A3Id1vkYR1Be0p/NaN3R7jU0WwHRxDscpELOnHsDo5zGDpPks0f6IVWaM27Am0oGCiDfvGW2ltRT6teeOfIzfwGfJpP4uAFRRjWJkY2UHZ92j1qHbeiec8RlH7wzkcX3JD93MAH/00jIqFPhxeuIp3wr2ouj2Ad+n92JJL0t8OfYdkd72oXegGY2wDfnB3ZFp+o4VpiSU32nFksR/vLV7Dm3PfQjP1Jd6iwJemOlE+7ZD0isU+vD7bgzfmeiD3m0WO/fCu60cJLEptUD7TLaT4TETTGsukPCn9Vsi9ZlARQPlCNtHnPdY5FQryUY3ZpJxynjmWOmKDcqiRXXqwdLR09gLSfGaRjJx0ZARsyBxnaUYm6emkb+/xymCB+AEcw7HcUlce/lIp44bNDXbQaRaRwZR0au5VI/J667H3CosRe7+vRx5Jbp8RL15rwB6WgQY6nKpO4FRIoXDuPGxrN0/K2hIA+fTsETP2d+mgbj8BddsJFNv1yL90GkVOA0o7a1DwTR3UX9TgYMun0gESgy3AFQJkymVzOynnXDdBRcAsOYON0q1VLtKHTcgZMkmH5gw10i0b6YZxyuqQHZcfRipl9G1qD804paIox2wxpa8JxQ490Saal8/EpfcMCr6uRX5PnXTbfbTHwilRBGyx1HhRolRgbbxtll230qZaGFDM8ligbfpEolzylQ4Hzp1C4cValJ2tkfYPnD+FYqJfwqtdR0Wxbb7AbbPsnt7uw9HH9yo1IQdSvWaB24IpZRNFlcsiUc0mqip3XGeq0jvTJnuqzywcDDvgfXSvcgtP+vTq1iavZ812UO+Zo0pqF6W3CWUdVASiyQVhsKJuAxWlVkqDYqKFcmeJcgx/tttYicPh2LInrJrpQIrfLOS4LZulRJkrznQ5d5yCwp7T2H/RsPk8+bDv8Ygn/Oxw2AF6MjI6qOXxNdkcS/WbY3KPWcjwWATFiEnIcJkE+UhDjBo9pg3x+Bob+Nf4SpzWMkjDMnngQaSy+s7g/Gu37KJ63oGicBcK57ugXnDg1aBDrCJbP7WbNLnjMf8/tRNum/zHkyev9Ny/Xd20elPPwvp6dP3lrb8AHszP3uwv5hVO/hs48fwAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;clean architecture 1&quot;
        title=&quot;&quot;
        src=&quot;/static/ac184c2acee15e27d0b7b1663d811ed3/d8118/clean-architecture-1.png&quot;
        srcset=&quot;/static/ac184c2acee15e27d0b7b1663d811ed3/d8118/clean-architecture-1.png 155w&quot;
        sizes=&quot;(max-width: 155px) 100vw, 155px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Next, the Use Cases represent the application-specific business rules that are responsible for orchestrating the flow of information and actions between different components in the system. These rules are typically specific to a given application and may involve many moving parts, including entities, interfaces, and other components.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ The direction of the arrows points to the direction of a dependency. That is to say &lt;code class=&quot;language-text&quot;&gt;A -&gt; B&lt;/code&gt;, should be read as &lt;code class=&quot;language-text&quot;&gt;A&lt;/code&gt; depends on &lt;code class=&quot;language-text&quot;&gt;B&lt;/code&gt;, or that &lt;code class=&quot;language-text&quot;&gt;A&lt;/code&gt; knows of &lt;code class=&quot;language-text&quot;&gt;B&lt;/code&gt;. Inversely, this means &lt;code class=&quot;language-text&quot;&gt;B&lt;/code&gt; does not depend on &lt;code class=&quot;language-text&quot;&gt;A&lt;/code&gt; and is not aware of the existence of &lt;code class=&quot;language-text&quot;&gt;A&lt;/code&gt;. This is not to be confused with the flow of control, which will be discussed separately.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the architecture diagram, the Use Cases are shown as being dependent on the entities, which contain the critical business rules that underpin the entire system. Notice the direction of the arrow, which indicates that the Use Cases depend on the entities, but the entities do not depend on the Use Cases.&lt;/p&gt;
&lt;p&gt;This direction of the arrow is important because it represents the direction of stability in the system. As we move in the diagram from lower-level components to higher-level ones, the components become more abstract and less volatile. This means that they are less likely to change and are therefore more stable.&lt;/p&gt;
&lt;p&gt;Conversely, as we move out of the diagram from higher-level components to lower-level ones, the components become more concrete and more volatile. This means that they are more likely to change and are therefore less stable.&lt;/p&gt;
&lt;p&gt;In general, the arrows in the architecture diagram should always point in the direction of stability, with higher-level components depending on lower-level ones. This helps to ensure that the system remains stable and resilient to change over time.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 291px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/792af902ab1916401407fe7a03cf027e/b3b34/clean-architecture-2.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAEwklEQVR42m1Va0yTZxSuc/uxxOmiDrMwCpPMZdmyZD+WzUgphWLL5qYW2q8X8AIdcmckzjkuLbcxb6ho3ERFmIjDKhgiUCbQOy2UtjC8xGn2D8f2Y+q2EBN6eXbeVhDMTvLmO/ne8zznOTnnfB+Pt8gALOOBt4z53oe3Y2vuHC/I81Se147vM37h+dpYQD57N/LQGxsB8Jbp9foXeP9nuZ7cl9jTOGOOK/LpWj53ZM+muDUQjatDCU45NjplELqVIbE7E9tGtLPFE/pzxhlX3GLsggn1whfZs/m3DrFqrPiPZK8G8rGCUNlkXTDTXernXIVBShIs+6XOn+vZHxTauJDYkwmVu3iGYRhWDvnyMJncEHFO370gTffkPxE45Eg0yQNbR3KQNVaGLY5spNl3QDlaCM5VDLmrEClWNcUoAgK7HBnegidn7ndIGIceT8ufmJmIU/lKfxc4FEiyKAMiixIJ5gx8PPwZpDYVPrFrIbHvhoT8TaatSDQrwGKSzFyACdD4Sh9MPJqIWyj5y1u158S+TJbVL7JwYYDYqoTMVY6N9iN413wM75mP4yNbI7a5dERMCs3yCClhxL4slN2uOxsmcz+eWr/dlfdYYGEBXEho5pBq5bDFVYt1N47g5b46rOiPHOavHjgMibOBlKvnlYYEVip9NO+R409HPK/216bctPFd7DJA5dJThu2uvYgePIrEkbNQey8j1dUKsbMVsvFLSBttA3+oCVuc3xBZOiIYRUDi2Ym6uydyePmTlWfEniy64PyJpE5iowD7AbzS34ANVObb1pPgm44ixtSIDZYmvGM5gVXGhnD5UpsmrFJo4QJsxEqmdM08rWdfX6KLo2yqAGvENmc23rccxArjt1hzrRprOysRZdDjtSt6rL1chdVdeqzsr0f88GHInHkQEIY1UjyeBa13fy+PNqAvcZQRKgMCkwKfDhfhg57vEXXxNKKvVuPN1grEdOjwRqcOcW2ViG2vwqq+erxlOoLtI7mLCDPBxPEKqeRUb6RkoVmJVJMKydZDWNXbSERViG0jwnYiai0Hn/w48lf21GGTozE8RgslE2HJVHUzr+beybw07+5nTbGwppRivek4VvTUgH9JBz6piu7Uh9W92q1H9I1jND77aQ6fNUXq24X6+ye14bGRufP+XhgbCytfjq3OSsSbm7Dmcg1e/7EC6y5WIapdh1giYyMltrJ55cIYgTUD6WP5j4fZ2DArmaw5w7pEkz9HpYPNYrKNSEmpyPUdPnQcCx+h8wAl2guxg8gsbKu4MCZlTIOym7XNC5ty68EtvtpbMp1AayQycf4kyp50nbK3pUN6lYP0uhrSKxpIu5UQXUuHqIUGupd8m9L/dPWmGceSj8OpO22b5Z6CWRYgNCvmRANcKJkRdBH5FVLzE5EYSHmXEvQ+mPSzYk4wQhvizp9tJuySj8O888O9C6mq8ZIZ1rEER0YwqVvhT2nn/MmddC5FjqhD4RcMZgRTaPfVFMswi4Ut2Dyp/aGHX+SrapE59/wr8e1EyqA6tNmgQWovnW51SOLcAdnYnn+Kvfpz1r/cMUuUPW8Gg2H5/C+ge7pvQ/nNgwX59orWnIGvBrRD+4xFQ5XnKzyH8tnd/C/geWX/AWbuNoiowMTZAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;clean architecture 2&quot;
        title=&quot;&quot;
        src=&quot;/static/792af902ab1916401407fe7a03cf027e/b3b34/clean-architecture-2.png&quot;
        srcset=&quot;/static/792af902ab1916401407fe7a03cf027e/b3b34/clean-architecture-2.png 291w&quot;
        sizes=&quot;(max-width: 291px) 100vw, 291px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Next up, we have the Interface Adapters.&lt;/p&gt;
&lt;p&gt;These adapters are responsible for converting incoming formats from the outside world into formats that are convenient for the use cases, and vice versa. They are the bridge between the higher-level use cases and the lower-level details of the outside world, such as database implementations, SDKs, APIs, user interfaces, I/O, and more.&lt;/p&gt;
&lt;p&gt;As with the other components, the direction of dependencies in the Interface Adapters layer should always point in the direction of stability. In this case, the adapters should depend on the interfaces defined by the use cases, and not the other way around.&lt;/p&gt;
&lt;p&gt;The Interface Adapters layer serves as a buffer between the highly volatile and specific external technologies and the stable use cases, allowing the system to evolve without being too tightly coupled to any particular external technology.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 450px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/188d3583e7e2de34068653e981b253f5/31401/clean-architecture-3.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 99.77777777777777%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAEuklEQVR42m1UbWxTVRi+a7eBfG0MWBgbA7ZBEAfbWGCuuIFrN4YGP1inDpj7YEQlgDHiD4G4hMn48OO3yIxBMSAJtF17e28/aHvbAq7iJCPESAKiieGHRn+xtb3n3Mf3dHHOhJuc3DfnPO9z3ve87/NK0rSvv7/fBEnKEnZqpK866V/dn/KWuNNy0WjaW/xDWikZTgfXfYDb+6sERmBBPtLjPkDKHCBxsDLtW+XRPfkc8XIgtgoI0z+4BIawQ/nQPXO5wODWwcrpvv+R9U9upCLWXqYuGIfPhLQz20h5i3WuLmNQSzmUEm74yljSNYulnSYDPjMENhW19UznmGJPaU19COZBd2UZSWcu444sGA4z/nbn4b6yHPeUFfjLnQ84cyDOBEZgEcgDI9//RZoe6azngQWPmCsL444ZhuEw4VelDKe0F/HqtT48G+uGLd6LdrKPay/gnroSAiOwwof5C8YFx1TK7GqFAtWMCecMBqcJiUA1tkc70RjrRVfiPbx8fS96E+9i58jbqNN24/lYF64FaiGwE86ZDP7Z4MEyZTLl0W6LLs8zko5s4IpkPFAr8BxFVB9+BdZwG7ZGd2Fr7E200GqN7oYtbKezdjTHenBXpSK5Zhqp8NNg8lxgrLdeQnz9AIIzMeHI1uGagQHtJdRqu9BEZK2xPagJH8di30co9J1GZehEhtgWsaM2shNHojsEIZKhDQzh+eDaug8lFqyQRbrcYWJ/eIuwndLZRBG0UmRV4QGsjZ6F5fpZbIx/hprYENZHPkELPUcDXbiNovxdLoLhryDCRWC+Erek+5f/CI8ZcEj8J/8aNNAbbSZwc3QvSoOfYrE8iKWek1jqPYVl3pMo9H9M6R5AU6QNFq0Tt3yrAaWYQ3sSulKYkNIqEcom6Jdz+A23Bc/IB7CF3ska3I9y1xksPn8UJV/T+uoois+9j0XKaTTHD2aexEKXj/qeAjzzOa7VEmHRiMQC5TKUyZQfepdSBV+ndOyZlKu1QRR8ewwl5w6j9MvDWPhNPyqvnqIidaEh1Ebv2YXflGWUnZkhsoTap8wtIVpzTBQl6TBTUZ7AEW0HNkY6KAI7tsb3ZkjLnSdQdmUQa4ODaLm+D1YqSh1hDml2GMOzhS9DIBc8Uj0gYayzntqGUdsY1Da441sDG7VNY6QdVr8d2xy7YfW9BatnH1o9XbA57dgcascWwoz612VajTrEIA4uuDK9yCMrFfipSR25OkgB/qsWNJIyakMdaLxoR9PFNjRdaEPjBTs2yB3YRGfuUINIldSSy4SuBceUUtI3e+pIPo9Im4KUCwWM+StxKG5HS6gbmy51wkKrxduNd2LtGA1UTaqEsHpGegseCY5JpVySzBn5xZr3ZIbDcBYfJwkalL7umo0H3hVIeGuQkNfjF7mM9ubAuCwJHTM2bOIIzkNKs/VN55oyJsK2Hq4WTKS9ubjzxUI+dmYhuz+Urz88N4f/eX4Wv/t5gf7z0Hx2e6iQ6woVgbBT4+tfsmkD1jw1qdVVqi7nGaL6RoA0LotlJjsHYk+cJdWVKkbfmJzcYSn78VP7Zm1OZqwDJnzfsTEVrDmRUkpl3bvku5RYwg5WDaZvvFaXwQgs+Uwn+QeUq3Xwyd5JSgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;clean architecture 3&quot;
        title=&quot;&quot;
        src=&quot;/static/188d3583e7e2de34068653e981b253f5/31401/clean-architecture-3.png&quot;
        srcset=&quot;/static/188d3583e7e2de34068653e981b253f5/31401/clean-architecture-3.png 450w&quot;
        sizes=&quot;(max-width: 450px) 100vw, 450px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In the outermost layer of Clean Architecture, we have the outside world which represents the low-level details such as the database, SDKs, APIs, User Interfaces, and IO. The arrows always point in the direction of stability, with the more inward direction indicating higher-level software and the more outward direction indicating lower-level software.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 646px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2b7d4d69f84f6754084c6c207972c12b/3ffe4/clean-architecture-4.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAE9UlEQVR42m2VCUxUVxSGx1bT1i0FBKy4srgXlNE0Ym2tNogLYKtGtA221qhpo6bu2qTghgMKFTdkE1AMFhSEAVSGfS0wI8g2YFAUNVbQVqvGwry5Xy+4xKU3OcnNe+d99//vvec8leqVAfToiq752UfYVJcV+jRkRQc1nNkZX5+0O/6SNiyoMPucz75qbJ7lq3r4+fm9o/q/IUHdL8rBqqVcG3Q3eeN9U/xcSJgpSPgSoidD2HjREf45rceX3atIOxYYUI5V1zdvQeHZgxtPUN/PDblC2lcQ6yI4aC84/LFC2ASFAyMVAgaZ8LcUhI4RRLnRfOrnpsSiZnU34wX0hbLWJ0x+XLCvHa0HpC82dStLlqouOiN0oxDnHSBFxnF7OOAsRKirwkEnbib81B6XVzPpNaUN0uajskgj56XFCz4K6bNA74qoGQE1E+R8HJQ7QvFHiNw+oLWBw/YIjZPC/oFcS9psXK9nwEvLfxkrNBSskMrcTWRKWNNkRMNQCbLhcbk9teVqqkon8jBvkFywJyLrXciygoPD4Ze+JsInor8Yo+mG1YDt00LNn+QthcwFAuNniKtSTa0DFxu9WdO8jSWNm/imfhNLqn8koWyGBPaVQHkhMgZC4DAzu/rS9vvK23tqsFW1tTT7oFsJuqVmUTQH8w1naLAnq2Uxc1q2sahpLQvrtrDg8lY8DN+jNqwipmwmZFtiLnFARA2GIGn9pAeVJdkLVW3VFwLR+ch9mW8S+qnQbM/jRjUrW7ey6OoavBr341IVy9iKKL4wBDKr0pfZ+uXcLhwLJY6Is3Jfg8crJHhQr9XsVd0uiDpJni/m1HnKv/ppUD+Eyw2zWdS8kcVNW3ExxOFSHolz6TFGlkbgrl/Hp4bl5BepoXQUSoYdItBBIcaNpnM7Tqha84+fJNsX5dQ05UGJtGIYRGXVXDzrNrCgdjOOeREMTdzF0NP+DMsKxaNqA1MlMKdYXqniYSi6MYjdtgqHHbmSqYlTXa9I3UuKJ0S5mESu3D+9BfcrRuFTtxqv6mVMr9qFoy4Ep8xg3Cr34n3pO+ZdWkFL4UjI7YVZKw9wp41ClCt1uiN7VMbLlQufxnvJe+VgFkmumP+whfx+nNLPxq1qFZ4F3+KlW4NnzjrmSydTKldwRC/zdX0Q+TJOSOAOS0XEu1NhKPpalQjWd86sv0XoEAkdJ0S2rIS8DzDnWBBb6YGXPIDp532ZrvVlXvEPHNV70pEj72BOL8TFwZiDHQWaAbSnrm09eudZ01DV5icFEC1POGhghwgfI63Ik8vuKe30pilrNBlZbmRkTqUuaxzmjH6yFHvKHGuIHC3VWXUSN4X60sS9Lysl+AGW15J31HNAqtxj2ynCumrXjvvpFjxI7k1H2vt0aN/jn5Te3MuwQlywg4gumHUnhwZzWxdQ71eH5WvNIcXQrG49vb6NEJns379TaIYrIkbWcuoQRObA7iBNLnhC1vC+EQp+/Ts5OJi7GVva0g3POw5vdJzEIqO66fT2JsInIctJPN1uobRvszP9/esQ0yN/O1PX/OE2a0XZ86Eg9hNupvs3pumvu77KeKvBBkvppenRmhsxy9s7ImZgOjRRKPudMIc4oRxWi6fR7txKWN1+SRcXGPzc5luwVxvti19AQANW53NzvQ3nfttpTN4dZUwOiKpNC92ZW5zrHdn6EtSDN7r1fza4v0j9uZqWAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;clean architecture 4&quot;
        title=&quot;&quot;
        src=&quot;/static/2b7d4d69f84f6754084c6c207972c12b/3ffe4/clean-architecture-4.png&quot;
        srcset=&quot;/static/2b7d4d69f84f6754084c6c207972c12b/0eb09/clean-architecture-4.png 500w,
/static/2b7d4d69f84f6754084c6c207972c12b/3ffe4/clean-architecture-4.png 646w&quot;
        sizes=&quot;(max-width: 646px) 100vw, 646px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;It’s important to note that the source code dependencies must only point inward towards stability, and violating this rule can result in a code smell. When the name of something in an outer circle is mentioned in an inner circle, or when data formats from an outer circle are used in an inner circle, it can be a sign that this rule is being violated.&lt;/p&gt;
&lt;p&gt;What about the flow of control? The flow of control should always follow the flow of dependencies. If a use case needs to call an external system or service, it should not do so directly because that would violate the Dependency Rule. Instead, the use case should call an interface or port defined in the outer layer of the architecture, and the implementation of that interface in the outer layer should handle the interaction with the external system or service.&lt;/p&gt;
&lt;p&gt;Similarly, if an external system or service needs to call into the system, it should do so through an interface defined in the outer layer. This technique ensures that all dependencies in the architecture flow inwards, towards the more stable and abstract layers, and that no component in an inner layer depends directly on a component in an outer layer.&lt;/p&gt;
&lt;p&gt;Overall, the goal is to use dynamic polymorphism to create source code dependencies that allow for flexibility and extensibility while conforming to the Dependency Rule, regardless of the direction of the flow of control.&lt;/p&gt;
&lt;h3&gt;But I am doing this already&lt;/h3&gt;
&lt;p&gt;This may look familiar even if you are new to it, but that can be very misleading&lt;/p&gt;
&lt;p&gt;The layers may look like the classic n-tier layers, but the flow of dependencies is different&lt;/p&gt;
&lt;p&gt;If you are not explicitly implementing clean architecture or at the very least if you are not concerned about solving the same challenges addressed by the clean architecture you are probably doing the classic n-tier.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 594px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7575fb0544e736defc6f442a04107439/d32a3/clean-architecture-6.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAER0lEQVR42m1VW0wcZRSeqs/lMv9sbTVafdBou1nLvUVuBi9IwAShC5SFQjU2tDWmXmLZ3dldbsVaKUubUNOXJr75gvSiW4hQWCmUqlRjjMaItmliojExvSTszj/zec5PC4s4yclM/jnnm++c850zmpZy4VPtfnWHtg6dIts29QjZOelPn5eBzHl+5jMERfZ/Y9Zcy2ABw2ObIoaw4aDXAHpcQP8WoO9RoFsAh12ww8Kxg/oX6DQ8KqZEe2A1WN0SmDSNFjsi7jCQDBlOwhTSCWRIdG+2Ybpsx58mE6YhZcjloMcgYP0OMd+dirECRi/oi7BDwkkykD8dCBq4eeQJLBx7Gr8ObMU/R55UZ05HOqygkPxRjpF+o3U1aIfIohc3KU0kg8IGBdygND8YrkLteCOe+2o3yqfbUDPRgN6RV3B9wA34MxjURljA7hS3EBDbllO2I/pZTsEKGhaDXfm4APUz+1A5tx/V06+hauYNlMSbUDX9Oiout6Nyeg9mTxWCfSkbC92UGWEssYvouVRkaTH9jjTcGPDgpXgLno83wzvTjpq5AwjG38S7E3uw68pB1M3uQ/FFL16YbsXC4DYCTXMsk+spJEKZeZqMCJObQKlaRBuHz9QgN96AoolaVI978fVQNhbDG2CR/RR1wzdWhyICzJuqR/h8HahZFKtL9JIaIqJDI4mMKGn40+Xf1IDai80KjFOcO/0iOT0Cq+thWD2bgdAmLJwsRMVkE54lnyq6/3X0KRXLGIQ1rMmQ/i26CPDQevuX426UzbRgx0QdWr9sQGIwB85QGeRRN+xoPqyhUiC6HQdjzNCLsqkmfDeUz7EKUJpijhjq36CLBHwo0746WICSyb0EWIu2sTb82ZeHZPdjsD/ywP5wCxLMsvtxvD26C3mTXpRSFvMnVwCJ4WWNdHeGOyz9uvytLwfVsf0q5WJqQuxEJRDYgEQ0F4n+Z7gBuHbMjZenfCrlCmL4R//W5ZRJQsOao5riIslkUpcMBD9/VRW8eHInfKS7HyklJ7yR6rcR145nYe9YIwqJXT7Ze7F6On+QYnWLMWRY+DXqUK4MKdmwrpyfT+SgnIRcTHVkeZTHfWgfrceBC15i5EPRZD1Kx2tRRj7fD+WpGJoYlo3FWHe1SJ1m6dDI8QSMny5DKemM61RMqeUrRjtVKQr47FIrYp+Uq2khuUmOpR0wsrIcQnoOOvVbPEYE6iCg4wf6+jsXGkjgPiWhEroz27dGG3GVJol9EkHdcWhcidDt5L2VlrocnIhaDnLRNBJUaEdGNuF61INLp7aT7cDvgx7IyEPcBGfRFAn2pR4gsWY5hLT77oI2y7B+m2eTVpmtit2RZpEsLLy/Xj1bgUyLRs1W80u+HJOKkZL20gECGW4ZoM0cFkmWk5JDqvWqBiRpwZ5FwOVexWzN1r4Hyr+AkMgi5ftJrJ+RzbLJoBhx6Izfkdu6/2P2L9wWRyUhOGOeAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;clean architecture 6&quot;
        title=&quot;&quot;
        src=&quot;/static/7575fb0544e736defc6f442a04107439/d32a3/clean-architecture-6.png&quot;
        srcset=&quot;/static/7575fb0544e736defc6f442a04107439/0eb09/clean-architecture-6.png 500w,
/static/7575fb0544e736defc6f442a04107439/d32a3/clean-architecture-6.png 594w&quot;
        sizes=&quot;(max-width: 594px) 100vw, 594px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;N-tiered architecture violates the Dependency Rule because the business logic layer knows about the data access and other infrastructure concerns, which means that high-level policies are dependent on low-level details. This violates the flow of dependencies and can lead to an unstable and difficult-to-maintain system. Clean Architecture, on the other hand, promotes a strict flow of dependencies where high-level policies depend only on abstractions and low-level details depend on high-level policies. This creates a more stable and maintainable system that is easier to change over time&lt;/p&gt;
&lt;h3&gt;Onion Architecture and Ports &amp;#x26; Adapters&lt;/h3&gt;
&lt;p&gt;Different architectural patterns can be used to achieve the same goal of separating concerns and dependencies in a software system. The onion architecture, ports and adapters, and clean architecture are examples of such patterns.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 918px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/33469a635bb80425e9424c7a3139217f/926ba/other-terminology.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 37.2%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAAA7DAAAOwwHHb6hkAAABMElEQVR42mVR7W7DIAzM+7/hfqydtG7tqiQEQ0LMR26HpVSTZsky3NnGnAfQaq0o9Hrw3A6UUnBabZ1rjM1yjqMZ3nhX5vX8zHjWDGATSQ5rHFHEQVePZR1ZUK2Zi0+oTKjBI8bZcntNSB7iHyjBYY8LXPjhYAWD5h2zfKN4NvEf9AeW5YZVA8LmIHJHceTdFerumOQLSTeLujxR5qvx3t3gtxlDH1VT4AQjsF1wyCcyX8xFsWuyc2FxkzdkNtQ9Gp74k+yfaPGdDS/YZeZDCUPXomuXo0NeHsgymqand/10+TGurELsQOsctVM+psRt0pKJN2r4WkpGVGpYE2rp4h/mnVuT8DsTl6BWZEthTGkzPGzeltLzh3Ob+54wTSOFD0b8tf5FCfIP7/dAPGd9Yb/w+iExLq219QAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;other terminology&quot;
        title=&quot;&quot;
        src=&quot;/static/33469a635bb80425e9424c7a3139217f/926ba/other-terminology.png&quot;
        srcset=&quot;/static/33469a635bb80425e9424c7a3139217f/0eb09/other-terminology.png 500w,
/static/33469a635bb80425e9424c7a3139217f/926ba/other-terminology.png 918w&quot;
        sizes=&quot;(max-width: 918px) 100vw, 918px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;©️ Image by Mark Seeman on &lt;a href=&quot;https://blog.ploeh.dk/2013/12/03/layers-onions-ports-adapters-its-all-the-same/&quot;&gt;his blog&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;While they may differ in their visualization and terminology, they share the same underlying principles and concepts. It’s perfectly fine to appreciate and have a preference for one over the other.&lt;/p&gt;
&lt;p&gt;I prefer the clean architecture as it provides a clear visualization of the different layers and their dependencies, which is backed by Uncle Bob’s book. However, I also find the terminology used in Ports and Adapters to be more explicit in describing the different components and their roles. Therefore, I may subtly introduce such terminology in my explanation going forward.&lt;/p&gt;
&lt;h2&gt;Specifics on some of the software layers&lt;/h2&gt;
&lt;p&gt;What else belongs in the domain core?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Interfaces&lt;/li&gt;
&lt;li&gt;Aggregate Roots&lt;/li&gt;
&lt;li&gt;Value Objects&lt;/li&gt;
&lt;li&gt;Entities&lt;/li&gt;
&lt;li&gt;Domain Services/ Use Cases&lt;/li&gt;
&lt;li&gt;Domain Exceptions&lt;/li&gt;
&lt;li&gt;Domain Events&lt;/li&gt;
&lt;li&gt;Event Handlers&lt;/li&gt;
&lt;li&gt;Validators&lt;/li&gt;
&lt;li&gt;Enums&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What else belongs in the infrastructure?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Repositories&lt;/li&gt;
&lt;li&gt;Db Context classes&lt;/li&gt;
&lt;li&gt;API Clients&lt;/li&gt;
&lt;li&gt;File System Access&lt;/li&gt;
&lt;li&gt;Cloud Service Access&lt;/li&gt;
&lt;li&gt;Email Clients&lt;/li&gt;
&lt;li&gt;SMS Clients&lt;/li&gt;
&lt;li&gt;System Clocks&lt;/li&gt;
&lt;li&gt;SDK types&lt;/li&gt;
&lt;li&gt;Identity&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Following these simple rules we have discussed so far is not a challenging task, and it can save you a lot of trouble in the future.&lt;/p&gt;
&lt;p&gt;By dividing your software into layers and abiding by the Dependency Rule, you will establish an inherently testable system, with all the advantages this entails.&lt;/p&gt;
&lt;p&gt;If any external parts of the system become outdated, such as the database implementation or the web framework, you can easily replace those obsolete elements with a minimum of fuss.&lt;/p&gt;
&lt;p&gt;Furthermore, you can lift and shift modules with ease. Your critical business rules, or your application business rules, can be reused in similar applications that may use different low-level details, such as varying technology implementations. For example, the same application core in a web API can be reused in a desktop application, as is.&lt;/p&gt;
&lt;p&gt;The same applies to the External agency implementations, the infrastructure, or adapters. The infrastructure implementations derived from clean architecture, such as API clients, would have no business rules knowledge and thus can be used in entirely different applications, as it.&lt;/p&gt;
&lt;p&gt;The million-dollar question is whether you can break these rules and still be following clean architecture principles. I firmly believe that you cannot, particularly the dependencies flow. The benefits of this architecture stem from its purity. This is not to say that it is a rigid architecture; there is a lot of flexibility built into it. However, the Dependency Rule is an absolute must.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 2000px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/11598ce5cbacd6c6110dd74b889cc565/1d07c/tingey-injury-law-firm-veNb0DDegzE-unsplash.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.60000000000001%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wgARCAANABQDASIAAhEBAxEB/8QAGgAAAQUBAAAAAAAAAAAAAAAAAAIDBAUHCf/EABYBAQEBAAAAAAAAAAAAAAAAAAUDBP/aAAwDAQACEAMQAAAB6cajYNGLIJ5TL//EABsQAAICAwEAAAAAAAAAAAAAAAUGAgMBBBIH/9oACAEBAAEFAvRXaCEsB2IIw69sMdk14GxapFXXyNdkcdf/xAAeEQACAgICAwAAAAAAAAAAAAABAgMSBBMAESKBof/aAAgBAwEBPwG+KcfHi1uswedp5x0WIfSIVVS9XSMI5odLXkJ2lfEevvP/xAAgEQABBAIBBQAAAAAAAAAAAAABAgMREgAhIhMjYYHw/9oACAECAQE/AavdV1dgUQ0G251xuXCTWUlRUnfcFUDgCTkHx97z/8QAIRAAAgIBBAMBAQAAAAAAAAAAAgMBBBIABREhExQxUYH/2gAIAQEABj8CLeBGqy669Sobei4cghzrDYl0nixRYIqC5pzDAx4GZnjnSnbXeRZlqfNCIIYsQHMrMvFkXkAGia5agnpyGYhpfdTpVPfdqo7vVU6LC0bggbCgeIyMMEC6yxKR/JGZEomJ0gLe00z9TGahqX6bqkh0HqWKRVn1sY6jwsDrr5r+Rr//xAAbEAEBAQEBAAMAAAAAAAAAAAABESEAQTFR8P/aAAgBAQABPyFgVlBNYApJOeRLnraYuNJSFryH69mH37wdi3auCONNVmJFSZC5NjjjMLga1+PV1ftarqr3/9oADAMBAAIAAwAAABAnz//EABoRAQACAwEAAAAAAAAAAAAAAAEhYQARQZH/2gAIAQMBAT8QTYz7oYIV4IGRgIhKdcVVvl5//8QAHBEBAAIBBQAAAAAAAAAAAAAAAREhMQBBUZHw/9oACAECAQE/EAZXN0FAPG9eBCBZaOh5i9s86//EABkQAQEBAQEBAAAAAAAAAAAAAAERIQAxYf/aAAgBAQABPxBM1cGBgv4gejghsk8FwlxoOkMzhAfvrCNuTttctTUkPp5MZwbD1Tp/FotdspQtSKJRKiogV//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;tingey injury law firm veNb0DDegzE unsplash&quot;
        title=&quot;&quot;
        src=&quot;/static/11598ce5cbacd6c6110dd74b889cc565/451a4/tingey-injury-law-firm-veNb0DDegzE-unsplash.jpg&quot;
        srcset=&quot;/static/11598ce5cbacd6c6110dd74b889cc565/953fe/tingey-injury-law-firm-veNb0DDegzE-unsplash.jpg 500w,
/static/11598ce5cbacd6c6110dd74b889cc565/0a251/tingey-injury-law-firm-veNb0DDegzE-unsplash.jpg 1000w,
/static/11598ce5cbacd6c6110dd74b889cc565/451a4/tingey-injury-law-firm-veNb0DDegzE-unsplash.jpg 2000w,
/static/11598ce5cbacd6c6110dd74b889cc565/c7e40/tingey-injury-law-firm-veNb0DDegzE-unsplash.jpg 3000w,
/static/11598ce5cbacd6c6110dd74b889cc565/120d2/tingey-injury-law-firm-veNb0DDegzE-unsplash.jpg 4000w,
/static/11598ce5cbacd6c6110dd74b889cc565/1d07c/tingey-injury-law-firm-veNb0DDegzE-unsplash.jpg 5180w&quot;
        sizes=&quot;(max-width: 2000px) 100vw, 2000px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;©️ Photo by &lt;a href=&quot;https://unsplash.com/@tingeyinjurylawfirm?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Tingey Injury Law Firm&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/veNb0DDegzE?utm_source=unsplash&amp;#x26;utm_medium=referral&amp;#x26;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ The above is a very bold remark but very good advice. Once you have a firm understanding of this and have respected the rules enough to gain experience you will stumble upon interesting scenarios that may require trade-offs, like the classic EF Core problem in . NET. You can make a trade-off and break the rule(s) but tread with care.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What if I grossly violate the rules anyway, what could go wrong?&lt;/p&gt;
&lt;p&gt;Then you choose pain or sorts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;You choose to marry frameworks&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You choose to marry the UI technology&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You choose to marry the database&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You choose to end up with something that is not testable&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You choose to deal with occasional cyclic dependency issues&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You choose developer spelunking&lt;/p&gt;
&lt;p&gt;Must I remind you of your speluncaphobia, agoraphobia and mazeophobia? You can’t handle spelunking.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You choose to forfeit the ability to lift and shift&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You choose productivity that is ever-decreasing with each new feature.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;🛑 That is a lot of baggage to take on&lt;/p&gt;
&lt;h2&gt;Code Demo (C#)&lt;/h2&gt;
&lt;p&gt;To see Clean Architecture at play let us run with a scenario where we are creating a voucher system for a retail company. Initially, the requirement is to be able to generate vouchers that can be applied for free delivery. It should be possible to validate and redeem these vouchers, with the latter only being possible once.&lt;/p&gt;
&lt;p&gt;We want to be able to store these vouchers but we are not sure about the details yet so we want to defer this requirement. As for generating the vouchers we have identified &lt;a href=&quot;https://github.com/bolorundurowb/shortid/&quot;&gt;shortid&lt;/a&gt; as the library that we shall be using. For this example, let us assume this is a complex integration.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The demo examples will make use of the terminology from Ports and Adapters&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Port&lt;/strong&gt;: an interface between the application and the external world, which defines a set of operations or services that the application provides or requires.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Adapter&lt;/strong&gt;: a component that implements a specific port interface, adapting it to the application’s internal architecture (This is infrastructure!).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let us start with identifying the inner circle, the domain entities.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(string Code, VoucherType Type, Discount Discount, bool Shareable, bool Redeemed)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NewVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DiscountType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;discountType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shareable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;discount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Discount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;discountType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;discount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shareable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Redeem&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Redeemed&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Discount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(DiscountType DiscountType, float Value)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Discount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DiscountType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;discountType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;discountType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DiscountType&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Amount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Percentage&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherState&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AlreadyRedeemed&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Valid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;NotFound&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherType&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Unknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Delivery&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;Voucher&lt;/code&gt; structure defines a public record with five properties: &lt;code class=&quot;language-text&quot;&gt;Code&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Type&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Discount&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Shareable&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;Redeemed&lt;/code&gt;. The &lt;code class=&quot;language-text&quot;&gt;Code&lt;/code&gt; property is a string that holds the unique identifier for a voucher, &lt;code class=&quot;language-text&quot;&gt;Type&lt;/code&gt; holds the type of voucher, &lt;code class=&quot;language-text&quot;&gt;Discount&lt;/code&gt; holds the discount applied by the voucher, &lt;code class=&quot;language-text&quot;&gt;Shareable&lt;/code&gt; indicates if the voucher can be shared, and &lt;code class=&quot;language-text&quot;&gt;Redeemed&lt;/code&gt; is a boolean indicating if the voucher has been used or not. Additionally, the &lt;code class=&quot;language-text&quot;&gt;Voucher&lt;/code&gt; structure has a static method named &lt;code class=&quot;language-text&quot;&gt;NewVoucher&lt;/code&gt; that takes in a &lt;code class=&quot;language-text&quot;&gt;code&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;type&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;discountType&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;value&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;shareable&lt;/code&gt; parameter and returns a new &lt;code class=&quot;language-text&quot;&gt;Voucher&lt;/code&gt; object.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;Discount&lt;/code&gt; structure defines a public read-only record with two properties: &lt;code class=&quot;language-text&quot;&gt;DiscountType&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Value&lt;/code&gt;. The &lt;code class=&quot;language-text&quot;&gt;DiscountType&lt;/code&gt; property is an enum that defines the type of discount (Amount or Percentage), and &lt;code class=&quot;language-text&quot;&gt;Value&lt;/code&gt; is the amount of the discount applied.&lt;/p&gt;
&lt;p&gt;There are three enums defined in this code: &lt;code class=&quot;language-text&quot;&gt;DiscountType&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;VoucherState&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;VoucherType&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;DiscountType&lt;/code&gt; has three values: &lt;code class=&quot;language-text&quot;&gt;Unknown&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Amount&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;Percentage&lt;/code&gt;, which are used to define the type of discount applied by a voucher. &lt;code class=&quot;language-text&quot;&gt;VoucherState&lt;/code&gt; has four values: &lt;code class=&quot;language-text&quot;&gt;Unknown&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;AlreadyRedeemed&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Valid&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;NotFound&lt;/code&gt;, which represent the state of a voucher. &lt;code class=&quot;language-text&quot;&gt;VoucherType&lt;/code&gt; has two values: &lt;code class=&quot;language-text&quot;&gt;Unknown&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Delivery&lt;/code&gt;, which define the type of voucher.&lt;/p&gt;
&lt;p&gt;In addition to the structures and enums, there is a method defined within the &lt;code class=&quot;language-text&quot;&gt;Voucher&lt;/code&gt; structure named &lt;code class=&quot;language-text&quot;&gt;Redeem()&lt;/code&gt;. This method sets the &lt;code class=&quot;language-text&quot;&gt;Redeemed&lt;/code&gt; property of a &lt;code class=&quot;language-text&quot;&gt;Voucher&lt;/code&gt; object to &lt;code class=&quot;language-text&quot;&gt;true&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Overall, this code provides us with a basic framework for working with vouchers, discounts, and their state as required by our client.&lt;/p&gt;
&lt;p&gt;Next let us move to the next circle, the application. We shall require use cases that honour the expected behaviour, namely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Generating a new voucher&lt;/li&gt;
&lt;li&gt;Redeeming a voucher&lt;/li&gt;
&lt;li&gt;Validating a voucher&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before diving into the details of these use cases, we can already identify that the use cases will need to trigger infrastructure. For example, the use cases will need to read, create or update voucher entries that we are storing and the generate voucher use case specifically will need to generate a new voucher code.&lt;/p&gt;
&lt;p&gt;If we were to have a direct dependency on infrastructure, this would validate our dependencies rule, which states, always depend in the direction of stability. We can apply Dependency Inversion in our favour to make the application own and define the contracts that should then be honoured by the infrastructure. Our use cases can then depend on and consume these contracts, hence not depending on something volatile, and in turn, our infrastructure can depend on and implement these contracts.&lt;/p&gt;
&lt;p&gt;Let’s look at what these contracts could look like&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherGenerator&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GenerateNewCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherRepository&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Upsert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TryGetVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;? &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first interface &lt;code class=&quot;language-text&quot;&gt;IVoucherGenerator&lt;/code&gt; defines a single method &lt;code class=&quot;language-text&quot;&gt;GenerateNewCode&lt;/code&gt; that takes in an optional &lt;code class=&quot;language-text&quot;&gt;CancellationToken&lt;/code&gt; and returns a &lt;code class=&quot;language-text&quot;&gt;Task&amp;lt;string&gt;&lt;/code&gt;. This method is responsible for generating a new voucher code and returning it as a &lt;code class=&quot;language-text&quot;&gt;string&lt;/code&gt;. The &lt;code class=&quot;language-text&quot;&gt;CancellationToken&lt;/code&gt; parameter is optional and allows for the cancellation of the task if needed.&lt;/p&gt;
&lt;p&gt;The second interface &lt;code class=&quot;language-text&quot;&gt;IVoucherRepository&lt;/code&gt; defines two methods &lt;code class=&quot;language-text&quot;&gt;Upsert&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;TryGetVoucher&lt;/code&gt;. The &lt;code class=&quot;language-text&quot;&gt;Upsert&lt;/code&gt; method takes in a &lt;code class=&quot;language-text&quot;&gt;Voucher&lt;/code&gt; object and an optional &lt;code class=&quot;language-text&quot;&gt;CancellationToken&lt;/code&gt; and returns a &lt;code class=&quot;language-text&quot;&gt;Task&lt;/code&gt;. This method is responsible for inserting or updating a voucher in the repository. The &lt;code class=&quot;language-text&quot;&gt;CancellationToken&lt;/code&gt; parameter is optional and allows for the cancellation of the task if needed.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;TryGetVoucher&lt;/code&gt; method takes in a &lt;code class=&quot;language-text&quot;&gt;string&lt;/code&gt; representing a voucher code, an &lt;code class=&quot;language-text&quot;&gt;out&lt;/code&gt; parameter voucher of type &lt;code class=&quot;language-text&quot;&gt;Voucher?&lt;/code&gt; and an optional &lt;code class=&quot;language-text&quot;&gt;CancellationToken&lt;/code&gt;. This method is responsible for retrieving a voucher from the repository if it exists, assigning it to the voucher parameter and returning true. If the voucher does not exist, it returns false. The &lt;code class=&quot;language-text&quot;&gt;CancellationToken&lt;/code&gt; parameter is optional and allows for the cancellation of the task if needed.&lt;/p&gt;
&lt;p&gt;Overall, these interfaces provide the necessary contracts for voucher generation and repository operations. By implementing these interfaces in classes, the code can be decoupled and modular, allowing for flexibility and maintainability. The &lt;code class=&quot;language-text&quot;&gt;IVoucherGenerator&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;IVoucherRepository&lt;/code&gt; interfaces can be used together to generate, store and retrieve vouchers, allowing the rest of the codebase to interact with vouchers without worrying about the implementation details of voucher generation and storage.&lt;/p&gt;
&lt;p&gt;Now that we have defined the contracts, let’s look at the use cases.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GenerateVoucherRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;VoucherType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DiscountType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DiscountType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Shareable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;GenerateVoucherRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ForFreeDelivery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;VoucherType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Delivery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DiscountType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Percentage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;GenerateVoucherUseCase&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GenerateVoucherUseCase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherCodeGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherCodeGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ?? &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ArgumentNullException&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherCodeGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Handle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;GenerateVoucherRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GenerateNewCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NewVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;VoucherType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DiscountType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Shareable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Upsert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RedeemVoucherRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Code&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RedeemVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;IsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;? &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;RedeemVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Valid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;IsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;RedeemVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Invalid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;? &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;IsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RedeemVoucherUseCase&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RedeemVoucherUseCase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RedeemVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Handle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RedeemVoucherRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TryGetVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Code&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;RedeemVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Invalid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;!.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Redeemed&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;RedeemVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Invalid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RedeemVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;RedeemVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Valid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// If this logic is used elsewhere, ideally this would be another use case&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RedeemVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Redeem&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Upsert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ValidateVoucherRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Code&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ValidateVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;State&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;? &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ValidateVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NotFound&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;VoucherState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;NotFound&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ValidateVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Valid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;VoucherState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Valid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ValidateVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AlreadyRedeemed&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;VoucherState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AlreadyRedeemed&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ValidateVoucherUseCase&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ValidateVoucherUseCase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ?? &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ArgumentNullException&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ValidateVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Handle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ValidateVoucherRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_voucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TryGetVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Code&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ValidateVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NotFound&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;!.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Redeemed&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            ? &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ValidateVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AlreadyRedeemed&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            : &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ValidateVoucherResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Valid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existingVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above defines three use cases related to voucher generation, redemption, and validation.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;GenerateVoucherUseCase&lt;/code&gt; class implements a use case for generating a new voucher. The class takes in an &lt;code class=&quot;language-text&quot;&gt;IVoucherGenerator&lt;/code&gt; and an &lt;code class=&quot;language-text&quot;&gt;IVoucherRepository&lt;/code&gt; object through its constructor. The &lt;code class=&quot;language-text&quot;&gt;Handle&lt;/code&gt; method of the class takes in a &lt;code class=&quot;language-text&quot;&gt;GenerateVoucherRequest&lt;/code&gt; object and an optional &lt;code class=&quot;language-text&quot;&gt;CancellationToken&lt;/code&gt;. The method generates a new voucher code using the &lt;code class=&quot;language-text&quot;&gt;IVoucherGenerator&lt;/code&gt; object, creates a new &lt;code class=&quot;language-text&quot;&gt;Voucher&lt;/code&gt; object using the &lt;code class=&quot;language-text&quot;&gt;Voucher.NewVoucher&lt;/code&gt; static method, and stores the voucher in the repository using the &lt;code class=&quot;language-text&quot;&gt;IVoucherRepository.Upsert&lt;/code&gt; method. The method returns the generated voucher.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;RedeemVoucherUseCase&lt;/code&gt; class implements a use case for redeeming a voucher. The class takes in an &lt;code class=&quot;language-text&quot;&gt;IVoucherRepository&lt;/code&gt; object through its constructor. The &lt;code class=&quot;language-text&quot;&gt;Handle&lt;/code&gt; method of the class takes in a &lt;code class=&quot;language-text&quot;&gt;RedeemVoucherRequest&lt;/code&gt; object and an optional &lt;code class=&quot;language-text&quot;&gt;CancellationToken&lt;/code&gt;. The method uses the &lt;code class=&quot;language-text&quot;&gt;IVoucherRepository.TryGetVoucher&lt;/code&gt; method to check if the voucher exists in the repository and is not already redeemed. If the voucher is valid, the method calls the &lt;code class=&quot;language-text&quot;&gt;Redeem&lt;/code&gt; method of the &lt;code class=&quot;language-text&quot;&gt;Voucher&lt;/code&gt; object, sets the &lt;code class=&quot;language-text&quot;&gt;Redeemed&lt;/code&gt; property to &lt;code class=&quot;language-text&quot;&gt;true&lt;/code&gt;, and stores the voucher in the repository using the &lt;code class=&quot;language-text&quot;&gt;IVoucherRepository.Upsert&lt;/code&gt; method. The method returns a &lt;code class=&quot;language-text&quot;&gt;RedeemVoucherResponse&lt;/code&gt; object indicating whether the voucher was successfully redeemed.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;ValidateVoucherUseCase&lt;/code&gt; class implements a use case for validating a voucher. The class takes in an &lt;code class=&quot;language-text&quot;&gt;IVoucherRepository&lt;/code&gt; object through its constructor. The &lt;code class=&quot;language-text&quot;&gt;Handle&lt;/code&gt; method of the class takes in a &lt;code class=&quot;language-text&quot;&gt;ValidateVoucherRequest&lt;/code&gt; object and an optional &lt;code class=&quot;language-text&quot;&gt;CancellationToken&lt;/code&gt;. The method uses the &lt;code class=&quot;language-text&quot;&gt;IVoucherRepository.TryGetVoucher&lt;/code&gt; method to check if the voucher exists in the repository and is not already redeemed. The method returns a &lt;code class=&quot;language-text&quot;&gt;ValidateVoucherResponse&lt;/code&gt; object indicating whether the voucher is valid, already redeemed or not found.&lt;/p&gt;
&lt;p&gt;That concludes the application concerns. Next, let us move to the infrastructure by implementing the contracts defined in the application.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;internal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherRepository&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InMemoryStore&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_inMemoryStore&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Upsert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_inMemoryStore&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CompletedTask&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TryGetVoucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;? &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_inMemoryStore&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TryGet&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;vouchers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;vouchers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SingleOrDefault&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Code&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Equals&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;code&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FromResult&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(!(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucher&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;internal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InMemoryStore&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ConcurrentBag&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_store&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_store&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Add&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TryGet&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;selector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;selector&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_store&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsEnumerable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PersistenceAdapter&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ServiceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_serviceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;PersistenceAdapter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SetupAdapterContainer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IServiceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddScoped&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_serviceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SetupAdapterContainer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ServiceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_serviceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BuildServiceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The above defines an in-memory store and an adapter class for persistence operations.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;VoucherRepository&lt;/code&gt; class implements the &lt;code class=&quot;language-text&quot;&gt;IVoucherRepository&lt;/code&gt; interface and uses an in-memory store to add and retrieve voucher objects. The class has a private instance of &lt;code class=&quot;language-text&quot;&gt;InMemoryStore&amp;lt;Voucher&gt;&lt;/code&gt; class and two public methods: &lt;code class=&quot;language-text&quot;&gt;Upsert&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;TryGetVoucher&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;InMemoryStore&amp;lt;T&gt;&lt;/code&gt; class is a generic class that provides an in-memory store for any type of object. The details are not of particular importance. The key thing here is that we could defer the decision of implementing a data store, which could have been a database, file storage, blob storage, etc, by implementing a trivial in-memory store. Once we have enough context to make this decision, all we need to do is implement a new concrete implementation of the interface and once tested and ready, simply swap the previous for the new in our bootstrapping.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;PersistenceAdapter&lt;/code&gt; class is a simple adapter class that initializes and sets up the IVoucherRepository object using the VoucherRepository class.&lt;/p&gt;
&lt;p&gt;Overall, these classes provide a basic framework for implementing persistence operations.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;10&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;internal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CodeGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherGenerator&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherGeneratorAdapterOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CodeGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherGeneratorAdapterOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ?? &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ArgumentNullException&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GenerateNewCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FromResult&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ShortId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Generate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;GenerationOptions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;UseNumbers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;UseNumbers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;UseSpecialCharacters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;UseSpecialCharacters&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            }));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherGeneratorAdapterOptions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;UseNumbers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;UseSpecialCharacters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherGeneratorAdapter&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ServiceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_serviceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;VoucherGeneratorAdapter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherGeneratorAdapterOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SetupContainer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IServiceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddScoped&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_serviceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SetupContainer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherGeneratorAdapterOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ServiceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddSingleton&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IVoucherGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CodeGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_serviceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BuildServiceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The defines a code generator class and an adapter class for generating voucher codes.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;CodeGenerator&lt;/code&gt; class implements the &lt;code class=&quot;language-text&quot;&gt;IVoucherGenerator&lt;/code&gt; interface and uses a third-party library called &lt;code class=&quot;language-text&quot;&gt;ShortId&lt;/code&gt; to generate short, unique, and random voucher codes. The class takes in a &lt;code class=&quot;language-text&quot;&gt;VoucherGeneratorAdapterOptions&lt;/code&gt; object through its constructor, which specifies the length of the code, whether to use numbers, and whether to use special characters. The class has a single public method, &lt;code class=&quot;language-text&quot;&gt;GenerateNewCode&lt;/code&gt;, that returns a new voucher code as a string wrapped in a Task object.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;VoucherGeneratorAdapter&lt;/code&gt; class is an adapter class that initializes and sets up the &lt;code class=&quot;language-text&quot;&gt;IVoucherGenerator&lt;/code&gt; object using the &lt;code class=&quot;language-text&quot;&gt;CodeGenerator&lt;/code&gt; class.&lt;/p&gt;
&lt;p&gt;Overall, these classes provide a basic framework for generating voucher codes using the &lt;code class=&quot;language-text&quot;&gt;ShortId&lt;/code&gt; library.&lt;/p&gt;
&lt;p&gt;Let us look at how this can be consumed, by observing some bootstrapping and a sample ASP.NET Core controller.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;11&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SetupAdapter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IServiceCollection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApplicationOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;persistenceAdapter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PersistenceAdapter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherGeneratorAdapter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherGeneratorAdapter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;settings&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;!.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;VoucherGeneratorOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;VoucherVoucherGenerator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;persistenceAdapter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;); &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;voucherGeneratorAdapter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Initialize&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApplicationOptions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VoucherGeneratorOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;VoucherGeneratorOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;12&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApiController&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;[controller]&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VouchersController&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ControllerBase&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;   &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ILogger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VouchersController&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;VouchersController&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ILogger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;VouchersController&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpGet&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;/vouchers/delivery/generate&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IActionResult&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FromServices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;GenerateVoucherUseCase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;useCase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;GenerateVoucherRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ForFreeDelivery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BeginScope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;               {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                   [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;query&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;               }))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;useCase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Handle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Created&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Empty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code shows how to consume the &lt;code class=&quot;language-text&quot;&gt;Adapters/Infrastructure&lt;/code&gt; in an ASP.NET Core application. The &lt;code class=&quot;language-text&quot;&gt;SetupAdapter&lt;/code&gt; method sets up the necessary adapters and initializes them with the services required for the application to work. The &lt;code class=&quot;language-text&quot;&gt;ApplicationOptions&lt;/code&gt; class is used to define options for the voucher generator adapter. The &lt;code class=&quot;language-text&quot;&gt;VouchersController&lt;/code&gt; is a sample ASP.NET Core controller that demonstrates the flow of control.&lt;/p&gt;
&lt;p&gt;We have all the moving parts, what about the project structure? This is quite flexible, and a decision you can make based on your project context or preferences and can leverage onto other patterns and practices you may be using like CQRS (Command Query Responsibility Segregation), DDD (Domain Driven Design), Vertical Slices etc. The key thing is however to continue to respect the dependencies’ rules. Let us look at an example project structure.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1018px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/0323c6610d8c96a9e1b2c2f41142186d/f759a/demo-dependency-diagram.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 47.199999999999996%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABcElEQVR42nVR2XKCQBDkUzxYTFQgXiCgiKjcq2WSqlS8z///hM4spqxo9KFrd2q7Z3t6JEVR8A+VCli5jLbjIl4ewNcHpMsdpusjosUeDdOCTO+Cd6+VHjYkMFlGTdNhuB5hCD+bw6TT6Huo1lUwxh7qnjas0O/GwEcviOEECfz3BZxJlNfiE+VZQ+GEsVvIMo2jMPRijmxF4y62SBYb8NWeRt/DDlOUS0XiybnTq5ZqSdh/rdVv0Gy10LFsWN4IfX+EpmFCfWugZXbz2qLRO5aDBvFeqrUbrRR8bZBR2ALTzYkcHXNXnGpOtXAkFmGPIzhRRrxT/i64/FcneIngfe8g2eMQ/TDJ4UYpBnGGyewDw3QGL+FwgwiCo7cNNLs2XOIJjs/nCOeflOlFK7K1KeNLhn8ggtU0DZqqwfZDDJOMzglMGt8ZBVTzPApd16GrKu71D7csU9ClQgFdcpZtz9fxZ7szUrqL5qViIefdb/kHGhEpmhNZTMsAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;demo dependency diagram&quot;
        title=&quot;&quot;
        src=&quot;/static/0323c6610d8c96a9e1b2c2f41142186d/f759a/demo-dependency-diagram.png&quot;
        srcset=&quot;/static/0323c6610d8c96a9e1b2c2f41142186d/0eb09/demo-dependency-diagram.png 500w,
/static/0323c6610d8c96a9e1b2c2f41142186d/1263b/demo-dependency-diagram.png 1000w,
/static/0323c6610d8c96a9e1b2c2f41142186d/f759a/demo-dependency-diagram.png 1018w&quot;
        sizes=&quot;(max-width: 1018px) 100vw, 1018px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We can observe that the Domain is maximally stable as it has no outgoing dependencies but has incoming dependencies, which is desirable as this is our policy. Next, we have the Application that knows of the Domain, followed by two adapters VoucherGenerator and Persistence that know of the Domain and, hence transitively know of the Domain. Lastly, we have a Web Host that knows of both adapters, as it needs to bootstrap them, and therefore transitively knows of everything. This know-all scenario is expected for Application Hosts and Tests.&lt;/p&gt;
&lt;p&gt;Let’s observe this again but with transitive references shown.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 1053px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8344023450419357dd4b8b31f6034305/c2a07/demo-dependency-diagram-transitive.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 45.599999999999994%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAA7DAAAOwwHHb6hkAAABrUlEQVR42mVS2XKjMBDkXwKYS9zh8IkxYBwgztZmj9jx2rn+/xN6R+Mila196JqRatRqdUvRdR0SmqbBtm0EQQDf9xH4Hor+Ad3pDd3xhXH3/Ir68QlpmiIMQ0RxDJ/mXdflc7IqI5lpmrw5mUxgGAZVHWGaIysrLNsO626PrNggXRbwPQ9CCHh+gCCZQlVV5pBCPgkty4JHgyr1uq7BoAuydYWcsNjdY9V/Z8J808ASLtSbGz43ihg5FNlodINpmETocs9ry0b984iBnnl3OFN9QX+8YHe4wL9NmVCKkaomVKVKaZlik3TTdiA88i2Kubec616cz5AsCkRJhiTLEWUzZKuSFAqekQhvk89ekHKl+XVCf3pFT0oGGcDzNYDhSxjt0wV52aB6PPAcz/5545kRze8zXb6Ekq1rzKotpoR53WJGHvF6U2PR7LCiQKSPIalMycNiN7C3ciYva8aUziRFxS9UpBf/QL1Wjaq8bNV9w7xqmXjRDphvezjCgUFBWBScST9ihB/G15T/AwUlv0758AP78wc97x33hP3lA1uyKKJQhOPwv/sKR7j4C92KKwIre4o1AAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;demo dependency diagram transitive&quot;
        title=&quot;&quot;
        src=&quot;/static/8344023450419357dd4b8b31f6034305/c2a07/demo-dependency-diagram-transitive.png&quot;
        srcset=&quot;/static/8344023450419357dd4b8b31f6034305/0eb09/demo-dependency-diagram-transitive.png 500w,
/static/8344023450419357dd4b8b31f6034305/1263b/demo-dependency-diagram-transitive.png 1000w,
/static/8344023450419357dd4b8b31f6034305/c2a07/demo-dependency-diagram-transitive.png 1053w&quot;
        sizes=&quot;(max-width: 1053px) 100vw, 1053px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The resulting solution structure looks as follows.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 404px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/9763fdb51c3abcccb4e92b0d9f4d7121/d2f6d/demo-solution-structure.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 188.86138613861388%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAmCAIAAABLWSz8AAAACXBIWXMAAA7DAAAOwwHHb6hkAAADvElEQVR42o1V13LiSBTlM4akgLKEEkotdUtqBWxg5mHWoeydqpn//4w9jb01L0i4HYoCnb73nnBZPL3+/vPrz69/319fXt7f35+fn/95esL/t7e3l9fXvu+app06C123HntyHNu24TWr8aRj27Ika5q22+2U2bOQthtVN+OMkILgMkIIY/QDJm0lefYsVFU1XL+sOaOsbZq6rod+GMexaRp8dAdsOV7KaN026Bmt933PGCvFqSzLkiRptrKiWJbdcdpz3jb4abM0Wa9Xy+Vyu93eqYw/2/PHsa0YpmVN3aZJYtu267qGYdwBgxhtpxr7wEtjkudVVY3DgIHzPI+i6A4YxJqmqe01SunYDyCMt9CMmYaxXK02m80c2DCsuMiTIoFIrRgapuAP4xHMJYcDiuP2KdoWluWEaQqFe953LR/HI62qvecFYQhwHMc7VZUm21ZVdOgGHikJFEZdaO153mq1+rb8tl6v5auZboO1nQZu9b2elwUqg+2Wd03dwHF5lruuA/zU5MJhNghzBZi3YuquG3renc7ny/kyDAOmSJLDzdIL2/ESWIqVlLKa0prWsBoKIhjQ2YAShqnp+kTbmu56HnQSNTlHKegE5WEvkLy9nkm20Y/jhT++d0NXZ2mK50DP5nru2xNPo0MvStw0LIoCgUAkq1J0H0XhfTDUCtPcPviwJCjreNd3HV7kWTafStG27QWXSz/2yHNLigI06deDj6XrmUvVbqd6weHHhVe0bK4GZazOshR47XomTfJxvSpLVpiZkYMdgPqci2zAcPjFZVDuJnkCjItNyy5oGWVxXTcf4JIUcRSjfiLifXulLPAeWPGC6PtZtM15V4uV0CAT8DwunVkJn20rsmSHmRV7QCLPUAtb5fR4HoYRLyYrf86sKE6UO8meih3awnCMUkgGwXAREjoJBpfYodi2CcmQDUQSYMzq+4Hv+2EYaBP7QIBVVXH3QctpTgssMDgEhGETeB5KupZpyXNSAa9ITkzM2EG/x+OxhtZ1czqdjuOAd6bZRnQ2G9zsxpl9cMHU48MjFhjcgi64mJnh2+s22LSciBAhEohtGKohHkix4wBiO45rW9akw3TDACe4fhxG+Ol4fChLIv+f5JkwfyxAxXZ9+xCWZQEnYkKwBIiopcj3lr6qOn5kHRDmrKpK2BNrCCTPf8X9Bbt+jMo5yaBwSQhGlb92BNjeR1YSZiRjldhkCBbw0r0d9PldFcTZPksykkOYvuvhbRC9/QoYwTl0PyvWoOGqxAKmWCZfbPs/o0N2oPh1fYIAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;demo solution structure&quot;
        title=&quot;&quot;
        src=&quot;/static/9763fdb51c3abcccb4e92b0d9f4d7121/d2f6d/demo-solution-structure.png&quot;
        srcset=&quot;/static/9763fdb51c3abcccb4e92b0d9f4d7121/d2f6d/demo-solution-structure.png 404w&quot;
        sizes=&quot;(max-width: 404px) 100vw, 404px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We can visualize what we have in code as follows&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 732px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/4479741dc645bce0577148f98eba468a/61a54/demo-visual.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 80.19999999999999%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAAA7DAAAOwwHHb6hkAAACYklEQVR42o1UXU8TQRTtv/TVF58hMeqD8oKJhjYmggGBWK1J/YgawQeKVCJaxBYbkGIptW4p1I3S3ULJlv3ozswe70xbUQTsTU4ye+/eM2fvx4YQcBxBoGsiCNBiAQ5fz6MRewwrFoeTycKXMX703nELnewOwBgjUgHvYxpsLgk/MYvW+hcV9Zmi/f3un6JCQrsNheJ1iP1PMqyIbB4oNbydoiDPjCBj7DSFvDQEUQpDFAbgm0uwKdPW52HlBtHM34RbGgf3OQLpr0zBWrtGGIBVnEBLXmIugq9fBN+4Cl6KEGGuDzzXD75yHv7PpFLFjBS4NgpengTbjkOIQCn0a+/Btu4RovD1aaVYWJsQOzGI6iOIH6+ohtyha1yCTT1h6tuaVHTd46h6DAadLdeH7XI0idjw22hSCTkPzm5K0OlyxvyMG4VhRIpjGPkaRe3QUv6X+gwim3cR3hzDlJ5o9+OvKeHHCNG+UbdreGekkTKX8aGeRcO1VXK6vooX1VmF5b01NWXdnJMVdoKFgzJGyw8xXo4jWnmKunug/PO7S3hQeY4YYaGWUZPTM+Hwt/u4o8UUqSkJg3+TW0z0NtiHLQ81Zx+G04BJ8GhsGG83QYJRoyQZ+19TjpoDeJTgdGB5Puq2R0odGIQ9z1XxnlZP7rC0+Pcc+vIz6CdMbGfxxtDU85XCHIa0FByfdRfvbMJunVLmNkYry4hWV5Eksg2rhhidJ3eyeKKvw5U16ElhhzCxW8JgaQEXctMKI1tpnFt5hrC2qEh7ViiN00a0Or+ot+YWLuXncHkjiVvaElhn+E+r4S/vBrRGXpFbngAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;demo visual&quot;
        title=&quot;&quot;
        src=&quot;/static/4479741dc645bce0577148f98eba468a/61a54/demo-visual.png&quot;
        srcset=&quot;/static/4479741dc645bce0577148f98eba468a/0eb09/demo-visual.png 500w,
/static/4479741dc645bce0577148f98eba468a/61a54/demo-visual.png 732w&quot;
        sizes=&quot;(max-width: 732px) 100vw, 732px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If we draw concentric circles based on that visualization with the various software levels, we would end up with the following&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 646px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2b7d4d69f84f6754084c6c207972c12b/3ffe4/clean-architecture-4.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAE9UlEQVR42m2VCUxUVxSGx1bT1i0FBKy4srgXlNE0Ym2tNogLYKtGtA221qhpo6bu2qTghgMKFTdkE1AMFhSEAVSGfS0wI8g2YFAUNVbQVqvGwry5Xy+4xKU3OcnNe+d99//vvec8leqVAfToiq752UfYVJcV+jRkRQc1nNkZX5+0O/6SNiyoMPucz75qbJ7lq3r4+fm9o/q/IUHdL8rBqqVcG3Q3eeN9U/xcSJgpSPgSoidD2HjREf45rceX3atIOxYYUI5V1zdvQeHZgxtPUN/PDblC2lcQ6yI4aC84/LFC2ASFAyMVAgaZ8LcUhI4RRLnRfOrnpsSiZnU34wX0hbLWJ0x+XLCvHa0HpC82dStLlqouOiN0oxDnHSBFxnF7OOAsRKirwkEnbib81B6XVzPpNaUN0uajskgj56XFCz4K6bNA74qoGQE1E+R8HJQ7QvFHiNw+oLWBw/YIjZPC/oFcS9psXK9nwEvLfxkrNBSskMrcTWRKWNNkRMNQCbLhcbk9teVqqkon8jBvkFywJyLrXciygoPD4Ze+JsInor8Yo+mG1YDt00LNn+QthcwFAuNniKtSTa0DFxu9WdO8jSWNm/imfhNLqn8koWyGBPaVQHkhMgZC4DAzu/rS9vvK23tqsFW1tTT7oFsJuqVmUTQH8w1naLAnq2Uxc1q2sahpLQvrtrDg8lY8DN+jNqwipmwmZFtiLnFARA2GIGn9pAeVJdkLVW3VFwLR+ch9mW8S+qnQbM/jRjUrW7ey6OoavBr341IVy9iKKL4wBDKr0pfZ+uXcLhwLJY6Is3Jfg8crJHhQr9XsVd0uiDpJni/m1HnKv/ppUD+Eyw2zWdS8kcVNW3ExxOFSHolz6TFGlkbgrl/Hp4bl5BepoXQUSoYdItBBIcaNpnM7Tqha84+fJNsX5dQ05UGJtGIYRGXVXDzrNrCgdjOOeREMTdzF0NP+DMsKxaNqA1MlMKdYXqniYSi6MYjdtgqHHbmSqYlTXa9I3UuKJ0S5mESu3D+9BfcrRuFTtxqv6mVMr9qFoy4Ep8xg3Cr34n3pO+ZdWkFL4UjI7YVZKw9wp41ClCt1uiN7VMbLlQufxnvJe+VgFkmumP+whfx+nNLPxq1qFZ4F3+KlW4NnzjrmSydTKldwRC/zdX0Q+TJOSOAOS0XEu1NhKPpalQjWd86sv0XoEAkdJ0S2rIS8DzDnWBBb6YGXPIDp532ZrvVlXvEPHNV70pEj72BOL8TFwZiDHQWaAbSnrm09eudZ01DV5icFEC1POGhghwgfI63Ik8vuKe30pilrNBlZbmRkTqUuaxzmjH6yFHvKHGuIHC3VWXUSN4X60sS9Lysl+AGW15J31HNAqtxj2ynCumrXjvvpFjxI7k1H2vt0aN/jn5Te3MuwQlywg4gumHUnhwZzWxdQ71eH5WvNIcXQrG49vb6NEJns379TaIYrIkbWcuoQRObA7iBNLnhC1vC+EQp+/Ts5OJi7GVva0g3POw5vdJzEIqO66fT2JsInIctJPN1uobRvszP9/esQ0yN/O1PX/OE2a0XZ86Eg9hNupvs3pumvu77KeKvBBkvppenRmhsxy9s7ImZgOjRRKPudMIc4oRxWi6fR7txKWN1+SRcXGPzc5luwVxvti19AQANW53NzvQ3nfttpTN4dZUwOiKpNC92ZW5zrHdn6EtSDN7r1fza4v0j9uZqWAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;clean architecture 4&quot;
        title=&quot;&quot;
        src=&quot;/static/2b7d4d69f84f6754084c6c207972c12b/3ffe4/clean-architecture-4.png&quot;
        srcset=&quot;/static/2b7d4d69f84f6754084c6c207972c12b/0eb09/clean-architecture-4.png 500w,
/static/2b7d4d69f84f6754084c6c207972c12b/3ffe4/clean-architecture-4.png 646w&quot;
        sizes=&quot;(max-width: 646px) 100vw, 646px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;That means we have satisfied Clean Architecture in our implementation 😃.&lt;/p&gt;
&lt;h1&gt;Tests&lt;/h1&gt;
&lt;p&gt;What about tests?&lt;/p&gt;
&lt;p&gt;Tests are an essential part of software development and they follow the Dependency Rule just like any other component of the system. They always depend inward towards the code being tested and nothing within the system depends on the tests. This makes them the outermost layer of Clean Architecture.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 648px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/6ecf882e78d94f124cc39b7fd868a4cb/244f0/clean-architecture-7.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 100.2%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAE5ElEQVR42m2UeVCVVRiHSZv6x2nGQFRSUTQqtxGn3NcpHZsWEOJ6r4KkBgQoKouKEBdQ2S4KKiCEERrXnMuSSiAaS8aiiKwhaMCMFLjgEiWh3uU8HVAZtc7MO+fM933n+d7l975mZs8s4KV+6z9rweLi+V+UTXm5msuZGZm/HknLrMnWaoqK8pRq/rZ48fv/LPliSP9eBsPbyksib6UmdevDQ8E/QBAs9y3+4OUtHgb4cS1m9+2KHG3kDnqG999Rq9VDnoc9edCu75nVczKrnehI8N4s8PAVeHkY8HEz4uVixG21gc9WC+wVAt+NtCfvb9dWn5v1LGPQs46+ewv+yT7+JyEhEBBsZJeEJXwESbMhbT7EvwPRthA+G+Fjj3BQGFGpuL4vpud45Zn5z0GvyHz1nim8SkQ4qHcbSfKErA8gfQakTEJkTEGkTYJ9oyFBQg9OgZ2LEc5KI0olHamJV4Ou/zZiMOR7TY0aEg9CWJSBVF/IWwa5H8PpmYgLk6FaWuVERIkVQjcGEqdJ+FgIWgT2zgZ8fag7qdMMwNphZF921g3UEfLv4YK8T0C3VALehQZLHlVZ0VQ1k0uVdtwvGQHFQxB5FhArwZGWMtf2JhwUdO+L6trde2202c22NpUpORFCI03iqAy1YCWidDE0W3O9fgY7WjxQNfujavLDtXYd1edkuCWvILLHS+BIhMyp9NJIUCBVZWedzbqrzsei0UBEmAGdAnFqBdROhabxhLZ5svyqPysaY1lSu5clNb44Vrtwp1wWqNgacehtGfosWOMgVeBNc9bRWLPOgpNaIqMQoduN5DphzJXFqLGls/49FFd8Wd4YyeQLGdhWpjGnKpaFNesprZBeldtgTJsoqz8DscHeyHp3rmamZ5r9kZejJTwCsX2LkSxHDJlzZCEm0XHRjk8bvHn/UgTjTu1lTFYUs89HsrDWnZIyO6iQwEPjYM84hLujBHrQ+n2GBJb9FEPoV5i2+hkeJX+IPmW6zKENovx1ttWrmF/nyeKyYBaUhrGoygfnug3c/VnK5+xriP3WMo9vgpvKyKZNtJ7SRZu1Ndco9RGhmNx9TQ+jFDxKeIs+rR2mc+Z0lE7Ep8qV5UXuLDvtgUvlWqrLp0Ppy5iyJ0ihj0LsmguOEqgOoa6u0tksByxvpRzowm0dbHYXAx2hGYPIlRdKXqWnwIKLhZOpzJ/KzcI3oEhWOF9qUCPDjZO2UWnCeTV3kw90JtI7akCLl4vzown0A9XnerY5yw+lxqKsMGbY8PAHSwkYJuU0DP0Jc/THbKQG+4EjIVi2ppNKT6A/LaWFMYOdkirHUcc3Kc24uYLS1SD8V0KMvLjHnAfRY+mNH09fgjW9sRMw7pFijpWeBX2EaZWLAbe13DiW0RJHl8WT4fC4oc82XJjze3zcHVzXyJwo9GxQmsTOpTxQT6NXLfMaZst9eTaELIEvFSYcV+n7YbdTk+6cbiyf+9xw0Ol0Q/v3HyuK57UdjG9lo5eEOomBPlUpDaxzfmxr5NlBYcBJArdupis9pbWwtmLes4zB9fRBXNcVi0qdVtMRFdFtDNwKHl8IXNaCqzRPDyF2BHBzb0x3fX5O7JG/Os2fjMCh/zu1+6FP3T7cUWNVVJCjrDn6ddzlbw9pmzNStQ3fpceVnjmhPNzRYvV0lr7o2b8EOsKp1+bjtgAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;clean architecture 7&quot;
        title=&quot;&quot;
        src=&quot;/static/6ecf882e78d94f124cc39b7fd868a4cb/244f0/clean-architecture-7.png&quot;
        srcset=&quot;/static/6ecf882e78d94f124cc39b7fd868a4cb/0eb09/clean-architecture-7.png 500w,
/static/6ecf882e78d94f124cc39b7fd868a4cb/244f0/clean-architecture-7.png 648w&quot;
        sizes=&quot;(max-width: 648px) 100vw, 648px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If the system architecture is centred around the use cases and the frameworks are kept at arm’s length, it should be possible to unit-test all the use cases without any frameworks in place. This is because tests are concrete and detailed, and they follow the Dependency Rule, making them easy to control.&lt;/p&gt;
&lt;p&gt;One advantage of tests is their flexibility in skipping boundaries. This allows developers to choose the type of tests to author, depending on the needs of the system. The combination of Inversion of Dependencies and Dependency Injection gives developers full control of this.&lt;/p&gt;
&lt;p&gt;In the case of the demo sample, developers could opt for integration tests that test at the API level. They could choose to use real dependencies for their infra implementation, mock them, or use doubles like an in-memory implementation. The same applies to unit tests, where developers can employ mocking or doubles to make the process easier.&lt;/p&gt;
&lt;p&gt;Clean Architecture doesn’t necessarily empower developers with things like end-to-end tests, but it also doesn’t hinder them. Developers can still write contract tests, behaviour-driven tests, targeted integration tests, and more.&lt;/p&gt;
&lt;p&gt;When a clean architecture is not followed, tests may not be integrated into the design as a first-class citizen. This leads to difficulties in testing and fragile tests. In such cases, tests are likely to be strongly coupled to the system being tested, making it challenging to maintain and change the system.&lt;/p&gt;
&lt;p&gt;A clear indication of a poorly designed test system is the strong coupling between tests and the system components. Such tightly coupled tests must change along with the system. Even a minor modification to a component can cause many dependent tests to break or require modifications.&lt;/p&gt;
&lt;p&gt;It is essential to understand that tests are not separate from the system being tested. Instead, they are integral parts of the system and must be well-designed to provide the benefits of stability and regression testing. Therefore, it is crucial to adhere to clean architecture principles to ensure that tests are appropriately integrated into the system design. By doing so, testing can be more effective, and changes to the system can be made with greater ease and confidence.&lt;/p&gt;
&lt;h1&gt;Summary&lt;/h1&gt;
&lt;p&gt;Give Clean Architecture a try and evaluate for yourself the claims it makes. Overall, however, we can summarize as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Clean Architecture is good for long-term software life&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Clean Architecture is good for stability and maintainability&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Clean Architecture is good testability&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The stability, maintainability and testability of your software are good for your long-term health&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Recommended Reading&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.oreilly.com/library/view/clean-architecture-a/9780134494272/&quot;&gt;Clean Architecture – Uncle Bob&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.martinfowler.com/books/eaa.html&quot;&gt;Patterns of Enterprise Application Architecture – Martin Fowler&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://www.domainlanguage.com/ddd/blue-book/&quot;&gt;Domain Driven Design - Eric Evans&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://12factor.net/&quot;&gt;12 Factor Application Principles&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;CQRS (Command Query Responsibility Segregation)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Acyclic Dependencies Principle&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Stable Abstractions Principle&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SOLID + GRASP Principles&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Azure Pipelines Standards and Practices]]></title><description><![CDATA[Photo by JJ Ying on Unsplash Azure Pipelines - Standards and Practices ✅ DO create pipelines in YAML committed in the relevant project…]]></description><link>http://www.drunkonmonads.com/Azure Pipelines Standards and Practice/</link><guid isPermaLink="false">http://www.drunkonmonads.com/Azure Pipelines Standards and Practice/</guid><pubDate>Sun, 19 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jjying?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;JJ Ying&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/4XvAZN8_WHo?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Azure Pipelines - Standards and Practices&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create pipelines in YAML committed in the relevant project repository and not via the classic UI approach or CLI.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; add shared variables to a variable group to avoid duplicated variables across various pipelines.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Add only truly global variables, that is any for which you would require the same value for all pipelines that use this without the need to customize for a single pipeline. An API key to a third-party service or a license key is a good example.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; leverage integrations to services like &lt;code class=&quot;language-text&quot;&gt;Azure Key Vault&lt;/code&gt; for managing user secrets and using those in pipeline runs.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; store &lt;code class=&quot;language-text&quot;&gt;secret&lt;/code&gt; variables with &lt;code class=&quot;language-text&quot;&gt;Keep this value as secret&lt;/code&gt; enabled. The default would be for Azure DevOps to store variables as raw text.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Always ensure your secrets are stored securely and aren’t hardcoded in your pipeline.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour parameters over variables for scenarios where you have a finite list of values as parameters will make use of a radio button group or dropdown for convenience.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; maintain an extensive retention policy for pipeline runs. This is important to track run history over an extensive period for example to see if test run performance is regressing, linting cleanups are on track, and the addition of tests in the solution is healthy.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; have a clear naming convention for your pipelines, making it easy to identify the type of pipeline (CI or CD), the target environment, and the project being built.&lt;/p&gt;
&lt;p&gt;Here’s an example of an Azure Pipelines naming standard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build pipelines: build-{projectName}&lt;/li&gt;
&lt;li&gt;Release pipelines: release-{projectName}-{environmentName}&lt;/li&gt;
&lt;li&gt;Deployment pipelines: deploy-{projectName}-{environmentName}&lt;/li&gt;
&lt;li&gt;Infrastructure pipelines: infra-{infrastructureType}-{projectName}-{environmentName}&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s a breakdown of each component of the naming standard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;{projectName}: the name of the project being built, deployed, or tested.&lt;/li&gt;
&lt;li&gt;{environmentName}: the name of the environment being deployed or released to.&lt;/li&gt;
&lt;li&gt;{infrastructureType}: the type of infrastructure being deployed or managed, such as aks for Azure   Kubernetes Service or appsvc for Azure App Service.
{testType}: the type of test being run, such as unit, integration, or end-to-end.&lt;/li&gt;
&lt;li&gt;{platform}: the platform being tested on, such as linux-x64 or windows-x64.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By following a consistent naming standard like this, it’s easier to quickly identify and locate the pipelines you need within Azure DevOps.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use templates to share pipeline configuration across projects. This ensures consistency in pipeline design and makes it easier to maintain pipelines.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; implement checks such as quality gates, code coverage requirements, and security scans as part of the pipeline.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; have a clear and concise description of what the pipeline is doing and include any relevant links to documentation or related systems.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; have a clear and concise description of what the pipeline is doing and include any relevant links to documentation or related systems.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; split long-running jobs across multiple stages. This promotes visibility and enables progress reporting as each stage is completed. Make sure any dependencies between stages are required to avoid unnecessary waits in the runs.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the appropriate pool directive for agents to help reduce build times by ensuring the build does not wait for an agent to become available.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that your deployment scripts are idempotent, i.e., running the script multiple times should not produce unexpected/different results.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour explicit versions of SDKs and other tooling in your pipelines. For example explicit node versions, .NET SDK versions or Bicep versions.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the appropriate pool directive for agents to help reduce build times by ensuring the build does not wait for an agent to become available.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ Microsoft frequently updates these images with the latest available tooling, bugfixes and patches. You can also specify a specific version for reproducibility reasons, especially when you want to maintain compatibility with certain libraries or frameworks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; have separate pipelines for CI/CD. This separation makes it easy to change the deployment strategy without affecting the build process.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; modularize your pipelines into templates for stages, jobs or steps once they start to become large or very focused. This makes things more manageable and readable, also opening up reuse potential.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Once you have the same logic copied across multiple pipelines this is often the smell that you could do with a template.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;🎇 &lt;strong&gt;DO&lt;/strong&gt; consider making use of caching to speed up pipelines by avoiding unnecessary computation or downloads. For example, by hashing a node package lock JSON file as a cache key, you can avoid doing a node install when the packages have not changed and are available in a cache.&lt;/p&gt;
&lt;p&gt;🎇 &lt;strong&gt;DO&lt;/strong&gt; consider making use of pipeline artefacts to make resources from one pipeline run available to another for download to speed up pipelines by doing certain computations or downloads once.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A key deciding factor between caching and artefacts is whether or not the artefacts are optional or mandatory. If optional use a cache, else artifacts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; that you only publish required artefacts to keep your pipelines lean.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; that you only download required artefacts to keep your pipelines lean.&lt;/p&gt;
&lt;p&gt;🎇 &lt;strong&gt;DO&lt;/strong&gt; consider comments in your pipelines for things that may not be easy to understand. However, avoid commenting on every single line and assume a basic understanding of Azure Pipelines as a prerequisite for any reader.&lt;/p&gt;
&lt;p&gt;🎇 &lt;strong&gt;DO&lt;/strong&gt; consider built-in tasks, particularly platform-independent ones to increase the portability of your pipelines over using things like PowerShell tasks.&lt;/p&gt;
&lt;p&gt;🎇 &lt;strong&gt;DO&lt;/strong&gt; consider condition-based stages to optimize your pipelines by not executing stages that are not required based off set conditional logic.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure you have monitoring and alerting in place for your pipelines, so you can be notified when something goes wrong.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ A healthy build and deployment process is only as good as the monitoring and alerting in place. Ensure that you have appropriate notifications and reporting in place so that you can quickly identify and remediate any issues that arise&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; expose secrets via logs in the pipeline runs or to any unauthorized users.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use pipeline variables to store sensitive data such as secrets, keys, or passwords. Instead, use Azure Key Vault or a similar secure storage service.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; create overly complex pipelines with unnecessary steps or dependencies. This can lead to longer build times and an increased risk of failure. Keep pipelines simple and focused on the task at hand.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use scripts or code snippets in your pipeline without proper testing and validation. This can introduce security vulnerabilities or errors that are difficult to diagnose&lt;/p&gt;
&lt;h2&gt;Examples&lt;/h2&gt;
&lt;p&gt;Here is a single pipeline example that accounts for most of the recommendations in this document with comments&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;yml&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Build pipeline for a .NET Core project&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Uses a pool of Microsoft-hosted agents&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Stores secrets in Azure Key Vault&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Includes linting, unit testing, code coverage, and security scanning checks&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Uses templates for pipeline configuration&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Has a clear description of what the pipeline is doing and relevant links&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Splits long-running jobs across multiple stages&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Uses the appropriate agent pool to reduce build times&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Has a separate pipeline for CI and CD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Has monitoring and alerting in place for the pipeline&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;pool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;vmImage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;ubuntu-latest&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;solution&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;**/*.sln&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildPlatform&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Any CPU&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Release&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;stages&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Build&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Build stage&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Build&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Build job&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-build.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;solution&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.solution }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildPlatform&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildPlatform }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildConfiguration }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo Build completed $(Build.BuildId)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Finish Build&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# The linting check step&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/eslint-check.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;workingDirectory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;$(Build.SourcesDirectory)&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Test stage&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Test job&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-test.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;solution&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.solution }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildPlatform&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildPlatform }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildConfiguration }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo Test completed $(Build.BuildId)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Finish Test&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Publish&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Publish stage&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Publish&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Publish job&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-publish.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;solution&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.solution }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildPlatform&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildPlatform }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildConfiguration }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo Publish completed $(Build.BuildId)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Finish Publish&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Variables that should be shared across pipelines can be stored in variable groups&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Secrets should be stored in Azure Key Vault or a similar secure storage service&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;MyVariableGroup&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Templates can be used to share pipeline configuration across projects&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# In this example, we have separate templates for .NET Core builds, tests and publish&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# These templates can be reused across different projects with minor modifications&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;templates&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-build.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-test.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-publish.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Use a clear and concise description of what the pipeline is doing&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Include relevant links to documentation or related systems&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# This will help team members understand what the pipeline does and how it works&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# It also provides a starting point for troubleshooting if issues arise&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# The example below includes links to the project&amp;#39;s wiki, issue tracker, and documentation&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;repositories&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;self&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;triggers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;development&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;git://github.com/MyOrganization/my-project.wiki.git&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;wiki&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;git://github.com/MyOrganization/my-project/issues.git&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;issues&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;git://github.com/MyOrganization/my-project/docs.git&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;docs&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Specify an appropriate agent pool to reduce&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create pipelines in YAML committed in the relevant project repository and not via the classic UI approach or CLI.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; add shared variables to a variable group to avoid duplicated variables across various pipelines.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Add only truly global variables, that is any for which you would require the same value for all pipelines that use this without the need to customize for a single pipeline. An API key to a third-party service or a license key is a good example.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; leverage integrations to services like &lt;code class=&quot;language-text&quot;&gt;Azure Key Vault&lt;/code&gt; for managing user secrets and using those in pipeline runs.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour parameters over variables for scenarios where you have a finite list of values as parameters will make use of a radio button group or dropdown for convenience.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; store &lt;code class=&quot;language-text&quot;&gt;secret&lt;/code&gt; variables with &lt;code class=&quot;language-text&quot;&gt;Keep this value as secret&lt;/code&gt; enabled. The default would be for Azure DevOps to store variables as raw text.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; maintain an extensive retention policy for pipeline runs. This is important to track run history over an extensive period for example to see if test run performance is regressing, linting cleanups are on track, and the addition of tests in the solution is healthy.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; have a clear naming convention for your pipelines, making it easy to identify the type of pipeline (CI or CD), the target environment, and the project being built.&lt;/p&gt;
&lt;p&gt;Here’s an example of an Azure Pipelines naming standard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build pipelines: build-{projectName}&lt;/li&gt;
&lt;li&gt;Release pipelines: release-{projectName}-{environmentName}&lt;/li&gt;
&lt;li&gt;Deployment pipelines: deploy-{projectName}-{environmentName}&lt;/li&gt;
&lt;li&gt;Infrastructure pipelines: infra-{infrastructureType}-{projectName}-{environmentName}&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here’s a breakdown of each component of the naming standard:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;{projectName}: the name of the project being built, deployed, or tested.&lt;/li&gt;
&lt;li&gt;{environmentName}: the name of the environment being deployed or released to.&lt;/li&gt;
&lt;li&gt;{infrastructureType}: the type of infrastructure being deployed or managed, such as aks for Azure   Kubernetes Service or appsvc for Azure App Service.
{testType}: the type of test being run, such as unit, integration, or end-to-end.&lt;/li&gt;
&lt;li&gt;{platform}: the platform being tested on, such as linux-x64 or windows-x64.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By following a consistent naming standard like this, it’s easier to quickly identify and locate the pipelines you need within Azure DevOps.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use templates to share pipeline configuration across projects. This ensures consistency in pipeline design and makes it easier to maintain pipelines.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; implement checks such as quality gates, code coverage requirements, and security scans as part of the pipeline.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; have a clear and concise description of what the pipeline is doing and include any relevant links to documentation or related systems.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; have a clear and concise description of what the pipeline is doing and include any relevant links to documentation or related systems.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; split long-running jobs across multiple stages. This promotes visibility and enables progress reporting as each stage is completed.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the appropriate pool directive for agents to help reduce build times by ensuring the build does not wait for an agent to become available.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; split long-running jobs across multiple stages. This promotes visibility and enables progress reporting as each stage is completed.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that your deployment scripts are idempotent, i.e., running the script multiple times should not produce unexpected/different results.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the appropriate pool directive for agents to help reduce build times by ensuring the build does not wait for an agent to become available.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ Microsoft frequently updates these images with the latest available tooling, bugfixes and patches. You can also specify a specific version for reproducibility reasons, especially when you want to maintain compatibility with certain libraries or frameworks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; have separate pipelines for CI and CD. This separation makes it easy to change the deployment strategy without affecting the build process.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure you have monitoring and alerting in place for your pipelines, so you can be notified when something goes wrong.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ A healthy build and deployment process is only as good as the monitoring and alerting in place. Ensure that you have appropriate notifications and reporting in place so that you can quickly identify and remediate any issues that arise&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use pipeline variables to store sensitive data such as secrets, keys, or passwords. Instead, use Azure Key Vault or a similar secure storage service.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; create overly complex pipelines with unnecessary steps or dependencies. This can lead to longer build times and an increased risk of failure. Keep pipelines simple and focused on the task at hand.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use scripts or code snippets in your pipeline without proper testing and validation. This can introduce security vulnerabilities or errors that are difficult to diagnose&lt;/p&gt;
&lt;h2&gt;Examples&lt;/h2&gt;
&lt;p&gt;Here is a single pipeline example that accounts for most of the recommendations in this document with comments&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;yml&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Build pipeline for a .NET Core project&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Uses a pool of Microsoft-hosted agents&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Stores secrets in Azure Key Vault&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Includes linting, unit testing, code coverage, and security scanning checks&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Uses templates for pipeline configuration&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Has a clear description of what the pipeline is doing and relevant links&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Splits long-running jobs across multiple stages&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Uses the appropriate agent pool to reduce build times&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Has a separate pipeline for CI and CD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Has monitoring and alerting in place for the pipeline&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;trigger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;pool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;vmImage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;ubuntu-latest&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;solution&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;**/*.sln&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildPlatform&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Any CPU&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Release&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;stages&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Build&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Build stage&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Build&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Build job&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-build.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;solution&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.solution }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildPlatform&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildPlatform }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildConfiguration }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo Build completed $(Build.BuildId)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Finish Build&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# The linting check step&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/eslint-check.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;workingDirectory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;$(Build.SourcesDirectory)&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Test stage&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Test job&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-test.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;solution&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.solution }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildPlatform&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildPlatform }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildConfiguration }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo Test completed $(Build.BuildId)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Finish Test&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;stage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Publish&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Publish stage&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;jobs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Publish&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Publish job&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;steps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-publish.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;parameters&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;solution&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.solution }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildPlatform&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildPlatform }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;buildConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;${{ variables.buildConfiguration }}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;script&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;echo Publish completed $(Build.BuildId)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;displayName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Finish Publish&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Variables that should be shared across pipelines can be stored in variable groups&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Secrets should be stored in Azure Key Vault or a similar secure storage service&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;variables&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;group&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;MyVariableGroup&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Templates can be used to share pipeline configuration across projects&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# In this example, we have separate templates for .NET Core builds, tests, and publish&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# These templates can be reused across different projects with minor modifications&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;templates&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-build.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-test.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;- &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;templates/dotnet-core-publish.yml&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Use a clear and concise description of what the pipeline is doing&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Include relevant links to documentation or related systems&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# This will help team members understand what the pipeline does and how it works&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# It also provides a starting point for troubleshooting if issues arise&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# The example below includes links to the project&amp;#39;s wiki, issue tracker, and documentation&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;resources&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;repositories&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;self&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;triggers&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;main&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    - &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;development&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;git://github.com/MyOrganization/my-project.wiki.git&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;wiki&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;git://github.com/MyOrganization/my-project/issues.git&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;issues&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  - &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;repository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;git://github.com/MyOrganization/my-project/docs.git&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;docs&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Specify an appropriate agent pool to reduce&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[GDPR technological implementation research (AWS Cloud)]]></title><description><![CDATA[Photo by Towfiqu barbhuiya on Unsplash GDPR technological implementation research (AWS Cloud) The General Data Protection Regulation (GDPR…]]></description><link>http://www.drunkonmonads.com/GDPR research (AWS Cloud)/</link><guid isPermaLink="false">http://www.drunkonmonads.com/GDPR research (AWS Cloud)/</guid><pubDate>Sun, 19 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@towfiqu999999?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Towfiqu barbhuiya&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/FnA5pAzqhMM?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;GDPR technological implementation research (AWS Cloud)&lt;/h1&gt;
&lt;p&gt;The General Data Protection Regulation (GDPR) is a European Union (EU) regulation that came into effect in 2018. It is designed to protect the privacy and personal data of EU citizens by setting strict guidelines for how data should be collected, processed, and stored. The GDPR has far-reaching implications for organizations that handle personal data, including those that use cloud services like Amazon Web Services (AWS). In this research, we aim to explore how the GDPR is translated into engineering, with a specific focus on the AWS Cloud platform. Our goal is to provide technical recommendations and best practices that will help AWS users achieve GDPR compliance and ensure the privacy and security of personal data.&lt;/p&gt;
&lt;h2&gt;Research Goals&lt;/h2&gt;
&lt;p&gt;The purpose of this research is to provide technical recommendations and best practices for achieving GDPR compliance on the AWS Cloud platform. Specifically, I aim to answer the following questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What practices are followed around data handling both at rest and in transit on AWS Cloud?&lt;/li&gt;
&lt;li&gt;How does GDPR impact what information we can store and how we store it, including in databases, files, logs, etc. on AWS Cloud?&lt;/li&gt;
&lt;li&gt;How does GDPR impact what support agents or developers can do when they need to get client data locally to reproduce issues on AWS Cloud?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By answering these questions, I hope to provide AWS Cloud users with a better understanding of how to implement GDPR requirements in their environments and ensure the privacy and security of personal data. The technical recommendations and best practices I provide are based on my analysis of the GDPR and how it can be implemented on AWS Cloud, as well as on industry standards and best practices for data security and privacy.&lt;/p&gt;
&lt;h2&gt;Useful resources&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://gdpr.eu/what-is-gdpr/&quot;&gt;What is GDPR, the EU’s new data protection law?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.enisa.europa.eu/publications/privacy-and-data-protection-by-design&quot;&gt;Privacy and Data Protection by Design&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Technical&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Consider client-side encryption of data before transferring to S3, using AWS SDKs that support encryption and decryption operations of objects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adopt tools in AWS that aid with better security and governance posture.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/security-hub/&quot;&gt;AWS Security Hub&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;AWS Security Hub is a security service offered by Amazon Web Services (AWS) that provides a comprehensive view of security alerts and compliance status across an AWS account. The General Data Protection Regulation (GDPR) is a regulation in EU law on data protection and privacy that requires organizations to take measures to protect personal data.&lt;/p&gt;
&lt;p&gt;AWS Security Hub can help with GDPR compliance in several ways:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Identifying potential security threats: AWS Security Hub provides a centralized view of security alerts from different AWS services, such as Amazon GuardDuty and AWS Inspector, which can help identify potential security threats and vulnerabilities that may impact the security of personal data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enabling compliance checks: AWS Security Hub provides compliance checks against a variety of industry standards and regulations, including GDPR. These checks can help identify non-compliant resources and provide recommendations for remediation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Automating compliance monitoring: AWS Security Hub can automate compliance monitoring by continuously checking AWS resources for compliance with GDPR requirements, such as data access control, data retention policies, and data protection measures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Facilitating incident response: AWS Security Hub can also help organizations respond to security incidents and breaches by providing alerts and notifications when security events occur, as well as by integrating with other AWS security services such as AWS CloudTrail and AWS Config.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/guardduty/&quot;&gt;Amazon Guard Duty&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Amazon GuardDuty is a threat detection service offered by Amazon Web Services (AWS) that continuously monitors for malicious activity and unauthorized behaviour within an AWS environment. GuardDuty can help with GDPR compliance by providing enhanced security for personal data stored or processed within the AWS environment.&lt;/p&gt;
&lt;p&gt;Here are some specific ways that Amazon GuardDuty can help with GDPR compliance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Detecting threats to personal data: Amazon GuardDuty can help detect threats to personal data stored or processed within an AWS environment. By analyzing log data and network traffic, GuardDuty can identify potential threats such as compromised instances, malware, or unauthorized access to sensitive data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Providing real-time alerts: GuardDuty can provide real-time alerts when it detects suspicious activity, allowing organizations to quickly investigate and respond to potential threats.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Automating threat detection: GuardDuty can automatically detect and alert on potential threats, reducing the need for manual monitoring and analysis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enabling compliance with GDPR security requirements: GuardDuty can help organizations comply with GDPR security requirements by providing visibility into security threats and unauthorized behaviour that may impact personal data. GuardDuty can also be integrated with other AWS security services, such as AWS Security Hub and AWS CloudTrail, to provide a comprehensive view of security and compliance posture.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Offering simplified compliance reporting: GuardDuty provides a range of pre-built compliance reports that can help organizations demonstrate their compliance with GDPR and other regulations.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In summary, Amazon GuardDuty can help organizations meet GDPR compliance requirements by providing enhanced security for personal data, automating threat detection and response, and simplifying compliance reporting.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/inspector/&quot;&gt;Amazon Inspector&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Amazon Inspector is a security assessment service offered by Amazon Web Services (AWS) that helps identify security vulnerabilities and compliance issues within an AWS environment. Amazon Inspector can help with GDPR compliance by providing a range of security assessments that can help organizations identify and remediate security issues that may impact personal data.&lt;/p&gt;
&lt;p&gt;Here are some specific ways that Amazon Inspector can help with GDPR compliance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Identifying security vulnerabilities: Amazon Inspector can help identify security vulnerabilities within an AWS environment, such as missing security patches, insecure network configurations, or weak access controls. By identifying these vulnerabilities, organizations can take steps to remediate them and reduce the risk of unauthorized access to personal data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enabling compliance assessments: Amazon Inspector can assess an organization’s compliance with a variety of industry standards and regulations, including GDPR. These assessments can help identify non-compliant resources and provide recommendations for remediation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Providing a range of assessment templates: Amazon Inspector provides a range of pre-built assessment templates that can help organizations assess the security of their AWS resources, including EC2 instances, network configurations, and applications.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Automating security assessments: Amazon Inspector can automatically perform security assessments regularly, reducing the need for manual security testing and analysis.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Facilitating incident response: Amazon Inspector can help organizations respond to security incidents and breaches by identifying vulnerabilities and misconfigurations that may have contributed to the incident. This information can help organizations remediate the underlying security issues and prevent similar incidents in the future.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In summary, Amazon Inspector can help organizations meet GDPR compliance requirements by identifying security vulnerabilities and compliance issues within an AWS environment, automating security assessments, and facilitating incident response.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/systems-manager/&quot;&gt;AWS Systems Manager&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;AWS Systems Manager is a management service offered by Amazon Web Services (AWS) that helps manage and automate operational tasks within an AWS environment. AWS Systems Manager can help with GDPR compliance by providing visibility and control over the configuration of AWS resources, enabling organizations to ensure that personal data is processed and stored in a secure and compliant manner.&lt;/p&gt;
&lt;p&gt;Here are some specific ways that AWS Systems Manager can help with GDPR compliance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Managing AWS resource configurations: AWS Systems Manager can help manage the configuration of AWS resources such as EC2 instances, databases, and network configurations. This can help ensure that personal data is stored and processed in a secure and compliant manner, with appropriate access controls, data retention policies, and encryption.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Automating security patching: AWS Systems Manager can automate the process of applying security patches and updates to AWS resources. This can help ensure that systems are up-to-date and secure, reducing the risk of security vulnerabilities that may impact personal data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enabling compliance checks: AWS Systems Manager provides compliance checks against a variety of industry standards and regulations, including GDPR. These checks can help identify non-compliant resources and provide recommendations for remediation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Facilitating incident response: AWS Systems Manager can help organizations respond to security incidents and breaches by providing tools for remote management and automation. This can help organizations quickly and efficiently remediate security issues and prevent further damage to personal data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Providing centralized management: AWS Systems Manager provides a centralized management console for managing AWS resources, making it easier for organizations to manage large and complex environments.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In summary, AWS Systems Manager can help organizations meet GDPR compliance requirements by managing and automating operational tasks within an AWS environment, enabling compliance checks, and facilitating incident response.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://aws.amazon.com/macie/&quot;&gt;AWS Macie&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;AWS Macie is a security service offered by Amazon Web Services (AWS) that provides automated data discovery, classification, and protection of sensitive data in an AWS environment. AWS Macie can help with GDPR compliance by identifying and classifying personal data stored within an AWS environment, and by providing tools to protect that data.&lt;/p&gt;
&lt;p&gt;Here are some specific ways that AWS Macie can help with GDPR compliance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Identifying personal data: AWS Macie can automatically discover and classify personal data stored within an AWS environment, including data such as names, addresses, phone numbers, and email addresses. This can help organizations better understand what personal data they have, where it is stored, and how it is being used.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Monitoring data access: AWS Macie can monitor data access and usage, providing visibility into who is accessing personal data and how it is being used. This can help organizations ensure that personal data is being processed and stored in a secure and compliant manner.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Enabling data protection: AWS Macie provides tools for protecting personal data, such as data loss prevention (DLP) policies that can help prevent data exfiltration or unauthorized access to personal data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Automating compliance checks: AWS Macie can automatically perform compliance checks against a variety of industry standards and regulations, including GDPR. These checks can help identify non-compliant resources and provide recommendations for remediation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Facilitating incident response: AWS Macie can help organizations respond to security incidents and breaches by providing tools for identifying and remediating data breaches or other security incidents involving personal data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In summary, AWS Macie can help organizations meet GDPR compliance requirements by automatically discovering and classifying personal data, monitoring data access and usage, enabling data protection, automating compliance checks, and facilitating incident response.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Create a plan to keep up with changes in TLS protocols and ensure support for the most secure HTTPS protocol. When vulnerabilities are discovered, a new TLS versioned protocol is released, and it is important to keep up with these updates.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The purpose of the collection and processing of personal data should be clearly defined and documented. Be critical about reusing data for other purposes particularly if this is not communicated to the user.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Customer data requests have to adhere to this. For instance, if communicated indicated that specific data would stay in a given region that should not be violated and it should be clear for what duration the data would be available in another form and the intended use. Scenarios like this should be covered by the privacy policy documentation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ask the following questions regarding data retention&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What storage timescale do we communicate and adhere to?&lt;/li&gt;
&lt;li&gt;Is there a need for regular deletion of data beyond that timescale?&lt;/li&gt;
&lt;li&gt;Is there a need for anonymizing data beyond that timescale?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Pay attention to potential gaps in the encryption of data, and keep data on encrypted media. For example, on data requests, the receiving machine should have encryption of drives and the data should not be transferred through means that could unreasonably expose it, like sharing via another cloud provider or messaging application. These gaps need to be identified and addressed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Research your data collection mechanisms to identify when it necessitates that in the EU there needs to be a consent form shown to users. This however is usually not required when data is stored only for the operation of our application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;There is a need for regular risk assessments around the security of data. The cloud is very dynamic and adopting tooling to help keep up is recommended.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adopt AWS config to assess, audit, and evaluate the configuration of AWS resources to ensure compliance (compliance-as-code framework), including&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Ensuring that configuration does not drift out of compliance. For example, someone accidentally turns off the encryption of a drive&lt;/li&gt;
&lt;li&gt;Keep up with potential security weaknesses&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Choose conformance packs to get out-of-the-box best practices. General recommendation examples&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/awslabs/aws-config-rules/blob/master/aws-config-conformance-packs/Operational-Best-Practices-for-Amazon-S3.yaml&quot;&gt;Operational Best Practices for Amazon S3&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-acsc_essential_8.html&quot;&gt;Australian Cyber Security Centre (ACSC) Essential Eight Maturity Model and AWS managed Config rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-acsc-ism.html&quot;&gt;Australian Cyber Security Centre (ACSC) Information Security Manual (ISM) 2020-06 and AWS managed Config rules&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-amazon-cloudwatch.html&quot;&gt;Operational best practices for Amazon CloudWatch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-asset-management.html&quot;&gt;Operational best practices for Asset Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-aws-identity-and-access-management.html&quot;&gt;Operational best practices for AWS Identity and Access Management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-wa-Reliability-Pillar.html&quot;&gt;Operational best practices for AWS’ Well-Architected Framework Reliability Pillar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-wa-Security-Pillar.html&quot;&gt;Operational best practices of AWS’ Well-Architected Framework Security Pillar&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-BCP-and-DR.html&quot;&gt;Operational best practices for business continuity and disaster recovery&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-cis-critical-security-controls-v8.html&quot;&gt;Operational best practices for Center for Internet Security (CIS) Critical Security Controls v8&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-cis_top_20.html&quot;&gt;Center for Internet Security (CIS) Top 20 Critical Security Controls&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-cisa-ce.html&quot;&gt;Cybersecurity &amp;#x26; Infrastructure Security Agency (CISA) Cyber Essentials (CE)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-DevOps.html&quot;&gt;Operational best practices for devops&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-EC2.html&quot;&gt;Operational best practices for EC2&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-Encryption-and-Keys.html&quot;&gt;Operational best practices for encryption and key management&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-gxp-eu-annex-11.html&quot;&gt;Operational best practices for GxP EU Annex 11&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-load-balancing.html&quot;&gt;Operational best practices for load balancing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-logging.html&quot;&gt;Operational best practices for logging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-Management-and-Governance-Services.html&quot;&gt;Operational best practices for management and governance services&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-monitoring.html&quot;&gt;Operational best practices for monitoring&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-nist_privacy_framework.html&quot;&gt;Operational best practices for NIST privacy framework&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-Publicly-Accessible-Resources.html&quot;&gt;Operational best practices for publicly accessible resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/operational-best-practices-for-Security-Identity-and-Compliance-Services.html&quot;&gt;Operational best practices for security, identity and compliance services&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/security-best-practices-for-EKS.html&quot;&gt;Operational best practices for EKS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/security-best-practices-for-Network-Firewall.html&quot;&gt;Operational best practices for AWS network firewall&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/security-best-practices-for-aws-waf.html&quot;&gt;Operational best practices for AWS WAF&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/security-best-practices-for-Secrets-Manager.html&quot;&gt;Operational best practices for AWS Secret Manager*&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reduce the risk of secrets being exposed&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Consider &lt;a href=&quot;https://aws.amazon.com/secrets-manager/&quot;&gt;AWS Secret Manager&lt;/a&gt; with &lt;a href=&quot;https://docs.aws.amazon.com/config/latest/developerguide/security-best-practices-for-Secrets-Manager.html&quot;&gt;best practices enforced&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Adopt compliance as code in any other viable areas. For example, adopting this as part of the IaC to make sure non-compliant changes will not pass a gate and will not be rolled out.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You need to be able to produce, delete and audit data easily as this can be &lt;code class=&quot;language-text&quot;&gt;demanded&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Consider &lt;a href=&quot;https://aws.amazon.com/cloudtrail/&quot;&gt;cloud trail&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Carefully consider the logging approaches in use and their retention policies&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Anonymize data that is requested for debugging.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A simple approach would be to identify what data to anonymize like email addresses, phone numbers, names, etc., and have some automation that runs to apply any number of techniques like masking, encrypting, randomizing, and faking before that data is given to a support agent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Organizational&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;There must be organisational measures in place to ensure that personal data is not compromised by accident or deliberately
&lt;blockquote&gt;
&lt;p&gt;Particularly with data transfer requests, ensure that whoever received the data does so responsibly and terminates the data after the intended usage is concluded.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;Implement awareness and training of any policies and obligations internally to anyone who has access to data, environments that contain data, the configuration of environments, and any other updates that can cause compliance issues like exposure through code updates.&lt;/li&gt;
&lt;li&gt;Limit who has access to data.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Internally, organizations should implement data handling and security protocols that align with GDPR. This includes establishing clear guidelines on data access, regular training programs on data protection, and emergency response plans for potential data breaches. For instance, regular workshops on handling PII (Personally Identifiable Information) and conducting mock data breach exercises can significantly enhance GDPR compliance.&lt;/p&gt;
&lt;h1&gt;Contract related&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Ensure a clear outline of the following in your privacy policy documents
&lt;ul&gt;
&lt;li&gt;The subject matter and duration of data processing&lt;/li&gt;
&lt;li&gt;The nature and purpose of the processing&lt;/li&gt;
&lt;li&gt;The type of personal data and categories of data&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;The data controller’s obligations and rights&lt;/li&gt;
&lt;li&gt;Summary of required policy documents
&lt;ul&gt;
&lt;li&gt;Information security policy&lt;/li&gt;
&lt;li&gt;Business continuity plan&lt;/li&gt;
&lt;li&gt;Privacy policy&lt;/li&gt;
&lt;li&gt;Data retention policy&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Other recommendations&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Map out all personal data you collect and categorize it
&lt;ul&gt;
&lt;li&gt;Identify if any of that data needs to be anonymized&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;SQL Server allows for tagging data with classifications with useful tags out of the box and supports recommendations (which unfortunately seems to get royally wrong at times, and can be overly sensitive as shown below). These classifications are stored as extended properties on the columns so this can be scripted as part of DB creation and targeted in other scripts.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;Delete/stop collecting any data you do not need. This approach aligns with Article 25 of the GDPR, which states that &lt;code class=&quot;language-text&quot;&gt;the controller shall implement appropriate technical and organizational measures for ensuring that, by default, only personal data which are necessary for each specific purpose of the processing are processed&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Communicate intent of use and ensure that future use adheres to that. For example, if you collect phone numbers for 2-factor authentication, you cannot later use them to send bulk messages for some other reason or share those details with an external party.&lt;/li&gt;
&lt;li&gt;Identify sensitive data that needs to always be encrypted. For example,  credit card details that would typically fall under that category&lt;/li&gt;
&lt;li&gt;Anonymize production data used in other environments&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;If a software developer is looking to research GDPR, there are a few steps they could take:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Start by reading the official GDPR text to gain a foundational understanding of the regulation. This will help to familiarize the developer with the key terms and concepts of GDPR. The official text of GDPR can be found on the European Union’s website.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Explore available online resources and training materials, such as webinars, podcasts, and online courses. These can help to provide more detailed information on specific aspects of GDPR, as well as practical guidance on implementing GDPR in software development.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Engage with GDPR experts and legal professionals who can provide guidance and advice on GDPR compliance.   This can help to ensure that the developer has a clear understanding of how GDPR applies to their specific situation and can provide guidance on how to implement GDPR-compliant software solutions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Research best practices for GDPR compliance in software development. There are several resources available online that guide how to design, develop, and implement software solutions that comply with GDPR.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Participate in forums and online communities to share knowledge and experiences with other software developers who are also working on GDPR compliance. This can help to provide insights into the challenges and solutions of GDPR-compliant software development.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Overall, it’s important for software developers to have a comprehensive understanding of GDPR and to stay up to date on any updates or changes to the regulation. By taking these steps, a software developer can research GDPR thoroughly and gain the knowledge and skills needed to design and develop software solutions that comply with GDPR requirements.&lt;/p&gt;
&lt;p&gt;Navigating GDPR compliance within the AWS Cloud requires a multifaceted approach that encompasses utilizing AWS’s robust security services, internal organizational measures, and clear contract-related policies. By understanding the specific requirements of GDPR and leveraging AWS tools effectively, organizations can not only comply with EU data protection laws but also enhance their overall data security posture. This research serves as a starting point for AWS users to build a GDPR-compliant environment, ensuring the privacy and security of personal data in the cloud.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Much of GDPR falls under contract so it can be difficult to tell if the technological interpretation is complete, this would require guidance from a qualified and certified GDPR officer.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[General Software Development Standards and Practices]]></title><description><![CDATA[Photo by Call Me Fred on Unsplash General Software Development Standards and Practices General Standards and Practices Documentation…]]></description><link>http://www.drunkonmonads.com/General Standards and Practices/</link><guid isPermaLink="false">http://www.drunkonmonads.com/General Standards and Practices/</guid><pubDate>Sun, 19 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@callmefred?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Call Me Fred&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/fJSRg-r7LuI?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;General Software Development Standards and Practices&lt;/h1&gt;
&lt;h1&gt;General Standards and Practices&lt;/h1&gt;
&lt;h2&gt;Documentation Principles&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; Recognize that certain tasks such as setting up a new environment, establishing infrastructure, or registering services are often repeated. These recurring tasks can benefit immensely from thorough documentation. Advocate for a &lt;code class=&quot;language-text&quot;&gt;Run Book&lt;/code&gt; approach, where the documentation is designed to guide the reader—whether it’s someone else or your future self—through each step of the process. This ensures that anyone following the guide can easily replicate the process without unnecessary trial and error.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create a reference of all decisions of architectural relevance by employing Architecture Decision Records (ADRs). An architecture decision record is a short text file in a format similar to an Alexandrian pattern. (Though the decisions themselves are not necessarily patterns, they share the characteristic balancing of forces.) Each record describes a set of forces and a single decision in response to those forces. Note that the decision is the central piece here, so specific forces may appear in multiple ADRs.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; acknowledge that well-documented standards and practices are essential for any team that wants to be efficient, effective, and reliable. They provide a shared understanding of how things should be done, which helps to avoid confusion and errors. They also make it easier to onboard new team members and improve/maintain quality. It is important to do this for all operations, for exampled coding standards, infrastructure management standards, DevOps standards, expectations on team ceremonies and roles etc. Ensure that the team has the relevant processes and gates for reviewing things such as Pull Request, second pair of eyes on infrastructure changes etc., while avoiding red tape and rigidity. Save time by also identifying standards and policies that can be automated with things like linting.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These approaches align well with the principle of prioritizing &lt;strong&gt;working software over extensive documentation&lt;/strong&gt;. It doesn’t require an inordinate amount of time to document these processes. However, the quality of the documentation should not be compromised. High-quality, concise documentation can save time and effort in the long run, making it a worthwhile investment.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Programming Principles&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use consistent coding styles. Consistency in coding styles can help make your code more readable and easier to maintain, so it’s important to establish clear coding standards and guidelines that all team members can follow.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;In a recent project, the adoption of consistent coding styles, enforced through tools like ESLint for JavaScript, resulted in a significant reduction in merge conflicts and easier code reviews. This uniformity allowed new team members to quickly acclimate and contribute effectively.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use version control. Version control tools like Git can help you manage and track changes to your codebase over time, making it easier to collaborate with other developers and keep your codebase organized.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use continuous integration and delivery. Continuous integration and delivery (CI/CD) tools can help you automate your build, testing, and deployment processes, making it easier to deliver high-quality code more quickly and efficiently.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; write automated tests.: Writing automated tests can help you ensure that your code is functioning correctly and that changes you make to your code don’t introduce new bugs or errors.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A healthy test coverage helps to ensure that your library is both correct and robust, and can help to prevent regressions and other issues from creeping in as you add new features or make changes. It also helps to build confidence in your library among users, who can see that it has been thoroughly tested and validated.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;A compelling case for automated testing was observed in a complex application where continuous integration, coupled with rigorous testing, caught a critical bug before deployment. This proactive detection saved significant time and resources that would have been spent in post-release nightmares.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; follow best practices for performance. Optimizing performance can be a key consideration in many software development projects, so it’s important to be mindful of best practices for performance, such as reducing the number of database queries or minimizing the use of expensive operations.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; prioritize security. Security should be a top priority in all of your software development efforts, and you should always be mindful of potential security risks and vulnerabilities in your code.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; embrace dependency injection. Dependency injection is a technique for managing dependencies in your code and can help you create code that is more modular, flexible, and testable.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; practice defensive programming. Defensive programming is a mindset that emphasizes anticipating and guarding against potential errors, bugs, and other issues in your code. This can help you create more reliable and resilient code.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use consistent naming conventions. Consistent naming conventions can help make your code more readable and easier to understand, so it’s important to establish clear naming conventions and stick to them throughout your codebase.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; apply a library developer mindset on any task that you pick up.&lt;/p&gt;
&lt;p&gt;This means thinking about the code you’re writing as a potential reusable library that can be used by others in the future, rather than just a one-off solution to a particular problem.&lt;/p&gt;
&lt;p&gt;To apply this principle effectively, you should consider whether the code you’re writing has good potential for reuse. If so, it may be worth extracting it into a library.&lt;/p&gt;
&lt;p&gt;To determine whether code has good reuse potential, you should consider a few key factors. One important factor is the level of abstraction in the code - code that is highly abstracted and modular is generally easier to reuse in different contexts. You should also consider the specific problem domain that the code is addressing - code that solves a common problem or performs a common task may be more likely to be reused than code that addresses a very specific, niche problem.&lt;/p&gt;
&lt;p&gt;When deciding whether to extract code into a library, it’s also important to consider the maintenance burden of the library. If you extract code into a library, you’re committing to maintaining that library over time, fixing bugs, updating it to work with new versions of dependencies, and so on. This can be a significant investment, so you should be sure that the potential benefits of having a reusable library outweigh the costs of maintaining it.&lt;/p&gt;
&lt;p&gt;By applying a library developer’s mindset to all programming tasks, you can create code that is more modular, more reusable, and more maintainable in the long term. This can help to reduce duplication of effort, improve code quality, and accelerate development speed overall.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; Leave the campground cleaner than you found it. This means that you should always strive to improve the codebase and associated assets (such as documentation and tests) when working on a project, rather than simply adding new features or functionality.&lt;/p&gt;
&lt;p&gt;To apply this rule effectively, there are several actions you can take:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Observe documentation that is out of date, then update it. This helps to ensure that others who use your codebase can understand it and use it effectively. It also helps to maintain the quality of the project overall and can reduce confusion and errors in the future.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Observe code that violates your team’s standards and practices or principles, then address it. Consistency is key in software development, and adhering to established coding standards and principles can make the codebase easier to read and maintain over time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Observe missing test coverage in critical areas, then add it. Tests are a crucial component of software development and can help to ensure that the codebase is robust and reliable. Adding missing test coverage in critical areas can help prevent regressions and other issues from creeping into the codebase.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Observe technical debt, then address it. Technical debt is a term used to describe code that has been written quickly or without proper consideration, and which may require additional work or refactoring in the future. Addressing technical debt can help to improve the quality of the codebase overall, and can make it easier to maintain and extend in the future.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Of course, there may be situations where applying the Boy Scout rule would be a big distraction, requiring a lot of attention and time. In such cases, it is justifiable to move on, however, it’s important to track these issues in your backlog or issue-tracking system, so that they can be addressed at a later time.&lt;/p&gt;
&lt;p&gt;By following the boy scout rule, you can help to create a codebase that is clean, maintainable, and extensible, and that can be a valuable asset for your team and your organization.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; apply care to not introduce new technical debt. It’s important to apply care to not introduce new technical debt into your codebase. It can be tempting to take shortcuts or make compromises under pressure, but these decisions can lead to long-term problems and make it difficult to maintain or evolve the codebase over time.&lt;/p&gt;
&lt;p&gt;One way to avoid introducing technical debt is to seek a second opinion, particularly from someone who is disconnected or immune to the current pressure. This can help to provide a fresh perspective and ensure that decisions are made with the long-term health of the codebase in mind.&lt;/p&gt;
&lt;p&gt;To help identify potential sources of technical debt, consider the following factors that can impact the quality and maintainability of your codebase:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Performance: If code is poorly optimized or inefficient, it can lead to slow or unreliable performance, which can impact the user experience and scalability of the application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Evolvability: Code that is inflexible or tightly coupled can be difficult to evolve, leading to problems when new features or changes are required.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Observability: If code is difficult to observe or monitor, it can be challenging to diagnose and fix issues when they occur.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Security: Code that is not properly secured or has vulnerabilities can put the application and its users at risk.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Maintainability: Code that is difficult to understand or maintain can be time-consuming and expensive to work with, making it more difficult to fix issues or add new features.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Scalability: Code that is not designed to scale can limit the ability of the application to handle increasing amounts of traffic or data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cost: Code that is inefficient or wasteful can be expensive to operate and maintain over time.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Robustness: Code that is not properly tested or validated can be prone to errors or failures, which can impact the reliability and usability of the application.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By paying attention to these factors and avoiding shortcuts or compromises, you can help to ensure that your codebase is maintainable, scalable, and resilient and that it can serve as a valuable asset for your organization over the long term&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The decision to go into debt alters the course condition of your life. You no longer own it. You are owned - Dave Ramsey&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; embrace &lt;code class=&quot;language-text&quot;&gt;within reason&lt;/code&gt; functional concepts for code that is easier to reason about, less prone to bugs, and easier to consume and test.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Immutability: Immutability is the idea that once a variable is assigned a value, that value cannot be changed. This can make code easier to reason about, as you don’t have to worry about unexpected changes to variables.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Referential transparency/Purity: Referential transparency is the idea that a function’s output depends only on its input, and not on any external state. This can make functions easier to test, as you don’t have to worry about the external state affecting the results of your tests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;First-class functions: First-class functions are functions that can be treated like any other value in the language. This means you can pass functions as arguments to other functions, return functions from functions, and store functions in variables.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;H.O.F (Higher Order Functions): Higher-order functions are functions that take other functions as arguments, or return functions as output. This allows you to build more complex and flexible functionality by composing simpler functions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Disciplined state: Disciplined state means that state changes are done in a controlled and predictable manner. This can help to reduce bugs related to state changes and make code more predictable and easier to reason about.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Closures: Closures are functions that capture variables from their surrounding environment. This can be used to create functions with “memory” or to build more complex functionality by composing simpler functions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lazy evaluation: Lazy evaluation is the idea that values are only computed when they are needed. This can help to reduce unnecessary computation and make code more efficient.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By embracing functional concepts in your code, you can create code that is easier to understand, test, and maintain, and that is less prone to bugs and unexpected behaviour. However, it’s important to use these concepts within reason and to balance them with other design principles and patterns, as appropriate for your specific use case&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; be mindful of code style as a blocker. Does the style and structure of your code make it harder to read and maintain?&lt;/p&gt;
&lt;p&gt;The style and structure of your code can have a significant impact on its readability, maintainability, and overall quality.&lt;/p&gt;
&lt;p&gt;When code is poorly structured or styled, it can be difficult for others to understand and maintain. This can lead to slower development cycles, increased bugs, and higher technical debt. In contrast, well-structured and well-styled code is easier to read and maintain, making it faster and less costly to develop and maintain.&lt;/p&gt;
&lt;p&gt;To avoid code style as a potential blocker, it’s important to adhere to best practices and style guides for your programming language and framework. This means writing code that is consistent in terms of naming conventions, indentation, comments, and other formatting elements.&lt;/p&gt;
&lt;p&gt;In addition, you should take care to structure your code in a way that is easy to read and maintain. This might mean breaking down complex functions into smaller, more focused functions, or organizing code into well-defined modules or classes.&lt;/p&gt;
&lt;p&gt;By being mindful of code style and structure, you can help to ensure that your code is easy to read and maintain, which can accelerate your development process and improve the quality of your code overall.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; enforce simplicity.&lt;/p&gt;
&lt;p&gt;The virtue of simplicity cannot be overstated - simpler interfaces are easier to use for all kinds of users, and require less code to create, providing an obvious performance advantage.&lt;/p&gt;
&lt;p&gt;Design decisions can be difficult, and often require user research to be done well. However, keeping things simple is always the right thing to do. This means not just simplifying or making things seem simple, but truly striving for simplicity in all aspects of your code and interfaces.&lt;/p&gt;
&lt;p&gt;When creating code and interfaces, aim to do a little and do it well, for as many people as you can. This means creating interfaces that are straightforward to understand, with clear and intuitive functionality. It also means creating code that is focused and purposeful, with minimal complexity or unnecessary features.&lt;/p&gt;
&lt;p&gt;By enforcing simplicity in your code and interfaces, you can create software that is not only easier to use and understand, but also faster and more performant. You can also reduce the likelihood of bugs and technical debt, making your code easier to maintain and extend over time.&lt;/p&gt;
&lt;p&gt;So remember, when it comes to software development, simpler is almost always better. Strive for simplicity in everything you create, and focus on doing a little and doing it well, for as many people as you can.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Bugs hide behind less important but easily noticeable things or complexity&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; avoid overly WET code, otherwise known as &lt;code class=&quot;language-text&quot;&gt;write everything twice&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;write every time&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;we enjoy typing&lt;/code&gt;, or &lt;code class=&quot;language-text&quot;&gt;waste everyone&apos;s time&lt;/code&gt;. This means that you should strive to avoid duplicating code unnecessarily, as it can lead to more work and maintenance in the long run.&lt;/p&gt;
&lt;p&gt;However, it’s also important to recognize that there are times when duplication may be necessary or even preferable to the wrong abstractions. This means that in some cases, it may be better to have duplicated code that is easier to understand and maintain, rather than trying to create complex abstractions that are more difficult to work with.&lt;/p&gt;
&lt;p&gt;Duplication can also be a useful tool for further understanding how to make the right abstraction. By seeing where and how code is being duplicated, you can identify common patterns and determine where an abstraction may be appropriate.&lt;/p&gt;
&lt;p&gt;In general, the key is to find a balance between avoiding unnecessary duplication and creating abstractions that are too complex or difficult to work with. This means being mindful of where duplication is occurring and why, and seeking to create abstractions that are simple, intuitive, and easy to understand and maintain.&lt;/p&gt;
&lt;p&gt;By avoiding overly WET code and finding the right balance between duplication and abstraction, you can create code that is both efficient and maintainable, and that can be a valuable asset for your organization over the long term.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that all logs are emitted to console as structured and compact json logs. This follows the 12 factor Apps approach to logging and is ideal for log targets to analyze the logs. DO NOT ship logs directly to a log target, in the case of k8s a side car agent is responsible for scrapping pod logs and ensuring that they get shipped out to the sink and any other heavy lifting like dealing with network issues, buffering etc.&gt; A twelve-factor app never concerns itself with routing or storage of its output stream. It should not attempt to write to or manage log files. Instead, each running process writes its event stream, un-buffered, to stdout.&lt;/p&gt;
&lt;p&gt;✅ DO pay close attention to the size of log or metrics payloads. Overly large data payloads should be avoided. As a safety net the config limits the depth of destructuring and caps the string length, but care is still required as this can be bypassed with context and scopes.&lt;/p&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO NOT&lt;/strong&gt; repeat yourself. This principle states that every piece of knowledge or information within a system should have a single, unambiguous, and authoritative representation.&lt;/p&gt;
&lt;p&gt;When information is duplicated or repeated across a system, it can lead to inconsistencies, errors, and maintenance headaches. It can also make it difficult to update or modify the system, as changes may need to be made in multiple places.&lt;/p&gt;
&lt;p&gt;To avoid repetition and adhere to the DRY principle, it’s important to identify common patterns and extract them into reusable functions, modules, or components. This can help to reduce duplication and make code easier to understand and maintain.&lt;/p&gt;
&lt;p&gt;By following the DRY principle, you can create systems that are more reliable, easier to maintain, and less prone to errors and other issues. It can also make it easier to modify and extend the system over time, as changes can be made in a single place and propagated throughout the system.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Apply care to strike the right balance with DRY, premature abstractions can be worse especially if attained by speculating future usages.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO AVOID&lt;/strong&gt;  leaky abstractions. A leaky abstraction exposes details or complexities that should be hidden from the consumer, making the abstraction more difficult to use and maintain.&lt;/p&gt;
&lt;p&gt;A classic example of a leaky abstraction is an implementation of an HttpClient wrapper that leaks HTTP details out to the consumer. In this case, the HttpClient wrapper should abstract away the details of the HTTP protocol, making it easier to use and maintain. However, if the wrapper leaks HTTP details to the consumer, it becomes less useful and more difficult to work with.&lt;/p&gt;
&lt;p&gt;To avoid leaky abstractions, it’s important to carefully consider the scope and purpose of each abstraction you create. The abstraction should be designed to hide details and complexities, not to expose them to the consumer.&lt;/p&gt;
&lt;h2&gt;GIT&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; add at least two branch suffixes as part of new branch names, an indication of your name and change type to have the name syntax &lt;code class=&quot;language-text&quot;&gt;[name]\[change-type]\[devops-code]&lt;/code&gt;, i.e &lt;code class=&quot;language-text&quot;&gt;jane\bug\10111&lt;/code&gt;. By using this naming convention, you can create a branching hierarchy that is easy to navigate and manage. The name makes it easy for one to target specific branches, for example, to clean up their branches. The change types make it easy to navigate branches by the type of change, such as a new feature implementation, bug fix, architecture changes, or documentation-only changes.&lt;/p&gt;
&lt;p&gt;Here are the tags that you can use for the change type:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;feature&lt;/td&gt;
&lt;td&gt;New feature implementation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;bug&lt;/td&gt;
&lt;td&gt;Bug fix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;architecture&lt;/td&gt;
&lt;td&gt;Architecture changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;doc&lt;/td&gt;
&lt;td&gt;Documentation-only changes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;pending&lt;/td&gt;
&lt;td&gt;Work-in-progress branch that may likely be long-living&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; clean up remote branches after they are merged. An easy way to guarantee this is to configure a Pull Request to delete the branch automatically on merge.&lt;/p&gt;
&lt;p&gt;By cleaning up remote branches in this way, you can keep your repository organized and easy to navigate, and reduce clutter and confusion. It can also help to improve the overall quality and efficiency of your development process, as it reduces the need for manual cleanup and maintenance tasks.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the imperative mood in the subject line&lt;/p&gt;
&lt;p&gt;Using the imperative mood in the subject line helps to ensure that your message is clear, concise, and action-oriented. It also makes it easier for others to understand what changes are being made and why.&lt;/p&gt;
&lt;p&gt;For example, bad commit messages might include vague or uninformative subject lines, such as &lt;code class=&quot;language-text&quot;&gt;tweaks to package-info files&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;polishing&lt;/code&gt;. These messages don’t provide much information about what changes were made or why making it more difficult for others to understand the changes being made.&lt;/p&gt;
&lt;p&gt;In contrast, good commit messages use the imperative mood in the subject line to clearly describe what changes were made and why. For example, &lt;code class=&quot;language-text&quot;&gt;fix failing CompositePropertySourceTests&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;rework @PropertySource early parsing logic&lt;/code&gt;, or &lt;code class=&quot;language-text&quot;&gt;add tests for ImportSelector meta-data&lt;/code&gt;. These messages provide clear and concise information about the changes being made, making it easier for others to understand the context and purpose of the changes.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The idea is that instead of a commit message saying what has been done it should be read as this is what will happen when the commit is applied.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;.NET&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; target the highest .net support surface area you can reasonably achieve and aim for a health test coverage when creating libraries.&lt;/p&gt;
&lt;p&gt;Targeting the highest .NET support surface area means that you should aim to make your library compatible with the widest possible range of .NET applications and platforms. This will make your library more useful to a larger number of developers, and increase its potential for adoption.&lt;/p&gt;
&lt;p&gt;Achieving a high level of .NET support surface area can be challenging, as it may require incorporating features and APIs from multiple versions of .NET. However, it’s important to strike a balance between achieving high support surface area and maintaining compatibility with the specific versions of .NET that are relevant to your users.&lt;/p&gt;
&lt;p&gt;In addition to targeting a high support surface area, it’s also important to aim for healthy test coverage. This means writing comprehensive unit tests, integration tests, and other automated tests to ensure that your library functions correctly and reliably in a variety of scenarios.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In conclusion, adhering to established software development standards and practices is not just about maintaining code quality; it’s about building a foundation for sustainable and efficient software development. From the preciseness of documentation to the consistency in coding and strategic use of .NET frameworks, these practices pave the way for robust, scalable, and maintainable software systems. As we’ve seen through various examples, whether it’s through streamlined workflows in Git or the flexibility afforded by .NET’s broad support surface area, these standards are more than guidelines—they are pillars that uphold the integrity and success of our software development endeavors.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Testing Best Practices]]></title><description><![CDATA[Photo by ThisisEngineering RAEng on Unsplash Testing Best Practices Unit tests are an essential part of software development that help…]]></description><link>http://www.drunkonmonads.com/Unit Testing Best Practices/</link><guid isPermaLink="false">http://www.drunkonmonads.com/Unit Testing Best Practices/</guid><pubDate>Sun, 19 Feb 2023 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@thisisengineering?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;ThisisEngineering RAEng&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/AvGIBmvdcac?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Testing Best Practices&lt;/h1&gt;
&lt;p&gt;Unit tests are an essential part of software development that help ensure that code works as expected, both initially and in the future. To maximize the value of unit tests, it is important to follow best practices.&lt;/p&gt;
&lt;p&gt;This document provides a comprehensive set of testing best practices for developers to follow to create high-quality and low-maintenance tests that aid in building robust and maintainable codebases.&lt;/p&gt;
&lt;h2&gt;General&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; aim for your tests to meet the following positive heuristics&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Run fast&lt;/p&gt;
&lt;p&gt;Tests should run quickly so that developers can run them frequently and not be slowed down by the testing process. Slow tests can be a barrier to TDD and other agile practices and can slow down feedback cycles&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Not break often or be flaky&lt;/p&gt;
&lt;p&gt;Tests should be reliable and not break often, especially due to reasons unrelated to the code being tested, such as timing issues, race conditions, or other environmental factors. This can lead to decreased trust in the testing process and can be frustrating for developers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Not be high maintenance&lt;/p&gt;
&lt;p&gt;Tests should be easy to maintain, update and refactor as code changes, so they don’t become a burden to the development process. This is especially important in large and complex codebases where maintaining the tests themselves can become a time-consuming and error-prone task.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Easy to read and understand&lt;/p&gt;
&lt;p&gt;Tests should be easy to read and understand for developers who did not write the code being tested. This helps new developers on a team quickly understand what is being tested and how it’s being tested.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Have the same style and diligence as the code being tested&lt;/p&gt;
&lt;p&gt;Tests should follow the same coding standards and best practices as the code being tested so that developers can maintain and update the tests as easily as they can the code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Be deterministic&lt;/p&gt;
&lt;p&gt;Tests should be deterministic, meaning that they always produce the same output given the same input. This helps ensure that the tests are reliable and can be trusted.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Survive major refactorings&lt;/p&gt;
&lt;p&gt;Tests should survive major refactorings, meaning that they continue to work as expected even when large parts of the codebase are changed. This is important to ensure that developers can continue to rely on the tests even as the codebase evolves.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;High coverage of important functionality&lt;/p&gt;
&lt;p&gt;Tests should have high coverage of important functionality, helping to catch regressions and ensuring that changes don’t cause unintended side effects.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A good balance between unit tests, integration tests, and end-to-end tests, each serving its purpose in validating different aspects of the system.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO AVOID&lt;/strong&gt; the following negative heuristics of tests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;⚒️ Heavy work&lt;/p&gt;
&lt;p&gt;A heavy reliance on manual testing, with developers spending a lot of time manually testing the system and debugging issues.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🧪 Logic in tests&lt;/p&gt;
&lt;p&gt;Tests should focus on the behaviour of the code being tested rather than its implementation details. Including too much logic in tests makes them less readable, less maintainable, and more difficult to understand.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🪄 Magic values&lt;/p&gt;
&lt;p&gt;Tests should use clearly defined, meaningful values instead of arbitrary or hard-coded values. Magic values can lead to confusion and make it difficult to understand what the test is verifying.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;😔 Not writing tests because &lt;code class=&quot;language-text&quot;&gt;they are difficult&lt;/code&gt; or something is &lt;code class=&quot;language-text&quot;&gt;untestable&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Not writing tests is a common problem among developers, especially when they are working on complex or legacy codebases. However, skipping tests because they are difficult or deemed untestable can lead to major issues down the line, such as regressions or bugs that go unnoticed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔫 Shotgun surgery&lt;/p&gt;
&lt;p&gt;This can lead to unhealthy practices like reading private methods with reflection to test functionality that should be public, which can lead to brittle and difficult-to-maintain tests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🌝 Eager test&lt;/p&gt;
&lt;p&gt;Tests that are too eager expose a lot of irrelevant details about the system under test (SUT), which can distract the test reader from what the test is verifying. These details can change often and require frequent updates to the test code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;😬 Happy path&lt;/p&gt;
&lt;p&gt;Happy path testing only tests the paths where things go well, but often misses potential issues and edge cases. It’s important to test both the happy path and other potential paths to ensure the system under test behaves as expected in all situations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🦥 Slow Poke&lt;/p&gt;
&lt;p&gt;Tests that take too long to run can be a drain on productivity and can lead to frustration among developers. These types of tests can often be optimized by using techniques such as parallelization or avoiding unnecessary setup.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🦣 Giant&lt;/p&gt;
&lt;p&gt;Large tests are difficult to maintain and can cause problems if they fail unexpectedly. It’s best to break tests down into smaller, more manageable units that are easier to understand and maintain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🤡 Mockery&lt;/p&gt;
&lt;p&gt;Overuse of mocking can lead to tests that are difficult to read and understand, and can also make it more difficult to identify problems when they occur.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔎 Inspector&lt;/p&gt;
&lt;p&gt;Tests that violate the black box approach make assumptions about the inner workings of the system under test, which can lead to brittle and difficult-to-maintain tests.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🪰 Generous leftover&lt;/p&gt;
&lt;p&gt;Tests that depend on run order or data that is shared between tests can be difficult to maintain and debug, especially when they fail unexpectedly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🦸 Local hero&lt;/p&gt;
&lt;p&gt;Tests that only pass in specific environments are not reliable and can lead to false positives. Tests should be designed to run in any environment and not be dependent on specific configurations.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🐜 Nitpicker&lt;/p&gt;
&lt;p&gt;Tests that focus on irrelevant specifics that are likely to change frequently can be difficult to maintain and can lead to false positives.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;📢 Loudmouth&lt;/p&gt;
&lt;p&gt;Tests that clutter the console with diagnostic messages can make it difficult to identify problems when they occur.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🤥 The liar&lt;/p&gt;
&lt;p&gt;Tests that skip the red-green-refactor process, use mocked SUTs, or are not specific enough can lead to false positives and make it more difficult to identify problems when they occur.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🆓 Free ride&lt;/p&gt;
&lt;p&gt;Assertions that piggyback on an existing test when they should be split out can lead to false positives and make it more difficult to identify problems when they occur.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔮 Mystery guest&lt;/p&gt;
&lt;p&gt;Tests that use magic elsewhere or do not indicate the cause and effect between act, arrange, and assert can be difficult to understand and maintain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🤫 Useless test
Useless tests are those that do not provide any value to the project, and only exist to satisfy a code coverage metric. Such tests might pass or fail randomly, and require manual debugging to figure out what caused them to fail. This results in a waste of time and effort for the team. Always make sure that your tests are relevant and valuable to the project.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🪲 Flaky test&lt;/p&gt;
&lt;p&gt;Flaky tests fail under specific conditions like time of day, day of the week, or hardware configuration. These tests are usually caused by race conditions, timing issues, or random data. Flaky tests are frustrating for developers because they are hard to reproduce and debug. It is crucial to fix flaky tests as soon as possible and ensure that your tests run reliably in all environments.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;💹 High maintenance tests&lt;/p&gt;
&lt;p&gt;Tests that are high maintenance are those that are fragile and require constant updates as the codebase changes. UI-driven tests are a common cause of high-maintenance tests. Overly complex tests, tests that are tightly coupled to the implementation, and tests with a lot of setups are also more likely to be high maintenance. High-maintenance tests consume a lot of resources and can make it difficult to refactor the codebase.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🐡 Lost tests&lt;/p&gt;
&lt;p&gt;Lost tests are those that do nothing and have no value. These tests might have been good at some point but have since been refactored to oblivion or were never implemented in the first place. Lost tests add noise to your test suite, making it harder to determine which tests are meaningful. Always make sure that your tests are relevant to the current state of the project.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔏 Using uncleansed data&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Using prod data as-is in tests can expose sensitive information and pose a security risk. Always use sanitized or synthetic test data when running tests, to ensure that sensitive information is not exposed.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;⚙️ Ignoring business needs or issues&lt;/p&gt;
&lt;p&gt;Tests that focus only on the technology and ignore business needs or issues can result in software that does not meet business requirements. It is essential to involve stakeholders and understand the requirements of the software before writing tests. Tests should focus on ensuring that the software meets business needs and requirements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🕔 Involving testing late&lt;/p&gt;
&lt;p&gt;Testing late in the development process can result in a lot of bugs being discovered late in the development cycle, which can be expensive and time-consuming to fix. It is essential to involve testing early in the development process to catch bugs as soon as possible. Writing tests alongside the code can also result in more effective tests and a more stable codebase.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🤐 Secret catcher&lt;/p&gt;
&lt;p&gt;Secret catchers rely on exceptions happening in the code and being caught by the test runner. This approach can be brittle and difficult to maintain, as it relies on specific error messages and exceptions that can change over time. It is better to use a more proactive approach to testing, ensuring that the software meets the desired behaviour under normal conditions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;🔢 Line hitter&lt;/p&gt;
&lt;p&gt;Tests that are only written to increase the code coverage metric, without any consideration for the quality of the tests, are known as line hitters. Line hitter tests do not provide any real value to the software and can be misleading. It is important to write meaningful tests that ensure the software meets business needs and requirements.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use test doubles (such as mocks and stubs) to isolate the code under test from its dependencies. Test doubles can make it easier to write focused tests that only test the behaviour of the code under test.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use code coverage metrics to identify untested code. Code coverage can be a useful tool for identifying parts of the codebase that are not being tested, which can help guide the creation of new tests.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use property-based testing to generate large amounts of test data automatically. Property-based testing can be a useful technique for testing complex or edge-case behaviour.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use continuous integration (CI) system to run tests automatically on each commit. A CI system can help catch regressions early and ensure that the test suite is always up to date.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use version control systems to track changes in the tests. This makes it easy to roll back to a previous version in case of issues.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use code reviews to ensure that tests are well-written and adhere to best practices.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; prioritize test cases based on the risk and impact of failure. This helps ensure that critical functionality is always tested.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use test-driven development (TDD) to guide the development process. TDD can help ensure that the code is thoroughly tested and that new features are implemented correctly.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the classic &lt;code class=&quot;language-text&quot;&gt;AAA&lt;/code&gt; (Arrange Act Assert) and &lt;code class=&quot;language-text&quot;&gt;RGR&lt;/code&gt; (Red Green Refactor).&lt;/p&gt;
&lt;p&gt;The AAA and RGR patterns are two common testing patterns that help to write clear, maintainable tests. The AAA pattern is a three-step pattern that consists of Arranging the test, Performing an Action, and Asserting the results. The RGR pattern is a three-step pattern that consists of writing a failing test (Red), making the test pass (Green), and then Refactoring the code. Following these patterns helps to ensure that the tests are clear, maintainable, and reliable.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ When &lt;code class=&quot;language-text&quot;&gt;RGR&lt;/code&gt; is ignored there is the possibility of creating tests with false positives, also known as the &lt;code class=&quot;language-text&quot;&gt;liar&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; familiarize yourself with Fixtures and best practices around their usage.&lt;/p&gt;
&lt;p&gt;A fixture is a fixed state that the system is in for a test. Fixtures help to ensure that tests are reproducible and predictable. For example, if a test relies on a particular file being in a certain state, the test can set up a fixture to ensure that the file is in the correct state for the test to run. It is important to familiarize yourself with fixtures and best practices around their usage to ensure that tests are reliable and reproducible.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider live unit testing tooling and practices.&lt;/p&gt;
&lt;p&gt;Live unit testing is a tool that runs unit tests automatically as the code is being developed. This tool can help to identify issues quickly and efficiently. By running the tests automatically, developers can focus on writing code and receiving immediate feedback on the code’s behaviour. Consider using live unit testing tooling and practices to improve the speed and reliability of testing.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use data generation sparingly and only in cases where specific data is not of relevance.&lt;/p&gt;
&lt;p&gt;Data generation is a tool that helps to create test data automatically. It can help generate large amounts of data or data that would be difficult to create manually. However, it is important to use data generation sparingly and only in cases where specific data is not relevant to the test.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ Apply caution with tooling like AutoFixture.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; write more tests. In particular, areas that require tests at all times are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Algorithms&lt;/li&gt;
&lt;li&gt;Intricate business logic&lt;/li&gt;
&lt;li&gt;Helpers and Utilities&lt;/li&gt;
&lt;li&gt;Resolved bugs&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ In addition to having more test coverage that helps with more confidence to change existing code and ensuring that previously discovered regressions do not occur again, tests are very good at identifying issues, especially coupling. Code that violates certain core principles that ensure a healthy and maintainable code base is very difficult to test, writing more tests allows us to see this upfront.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; validate private methods by unit testing public methods.&lt;/p&gt;
&lt;p&gt;Validating private methods through their corresponding public methods ensures that all the code within a unit is being tested, including any private code that is called by the public methods. This practice helps prevent changes in private methods from breaking the functionality of public methods. To validate private methods through their public methods, a developer needs to create test cases that call the public methods with input data that exercise the private methods. The output of the public methods is then validated to ensure that the private methods have produced the expected results.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; keep an eye on test metrics. These should answer questions about how fast tests run, whether there are regressions, how often tests fail, whether there are any tests that stand out as flaky, and what the code coverage is.&lt;/p&gt;
&lt;p&gt;Test metrics can provide valuable insights into the effectiveness of your testing approach. Metrics can help answer questions such as: How long do tests take to run? Are tests failing more often than usual? Are certain tests consistently failing or passing? How much code is covered by tests? Tracking these metrics can help identify areas for improvement, such as slow tests or areas of code that need more coverage. It’s important to keep an eye on test metrics regularly and adjust your testing approach as needed to improve the quality and speed of testing.&lt;/p&gt;
&lt;p&gt;✅  &lt;strong&gt;DO&lt;/strong&gt; consider a data generator like &lt;a href=&quot;https://github.com/bchavez/Bogus&quot;&gt;Bogus&lt;/a&gt; paired builders.&lt;/p&gt;
&lt;p&gt;Data generators like Bogus can be very helpful for creating test data. Test data generation can be time-consuming, especially if the data needs to be complex or varied. By using a data generator, a developer can easily create a large amount of realistic data to use in testing. Paired builders are a common pattern for generating data that have relationships or dependencies between different objects. They can help create data that is more representative of real-world scenarios and make it easier to write tests that cover a variety of use cases.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Over time the dependency list can grow and it is quite cumbersome to have to modify tests to add new mocks&lt;/li&gt;
&lt;li&gt;Quite often most of the mocks do not require setup so you do not need to explicitly create the mock, it can be auto-created&lt;/li&gt;
&lt;li&gt;The code can be made more succinct and easier to read&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Often when a service is updated to add a new dependency, this indicates new behaviour and likely means you would add new tests, not modify existing ones. With this approach, you do not have to update the tests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; name mocks vs mock object instances accordingly. Mocks from &lt;code class=&quot;language-text&quot;&gt;AutoMoq&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;new Mock&amp;lt;T&gt;()&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;Mock.Of&amp;lt;T&gt;&lt;/code&gt; should have the suffix mock but not the object instances from &lt;code class=&quot;language-text&quot;&gt;mock.Object&lt;/code&gt; i.e userMock for the mock and user for the object. This distinction can go a long way in the readability of tests.&lt;/p&gt;
&lt;p&gt;The mocks should have the suffix Mock, while the object instances should not have this suffix. This helps in the readability of tests, making it clear which objects are mocks and which are not. For example, you can name the mock as userMock and the object instance as a user.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the name &lt;code class=&quot;language-text&quot;&gt;sut&lt;/code&gt; for the &lt;code class=&quot;language-text&quot;&gt;system under test&lt;/code&gt;. This small detail shines particularly when the test is heavy in the arrange stage, it needs to be clear what the sut is.&lt;/p&gt;
&lt;p&gt;It is a good practice to use the name sut for the system under test in your tests. This makes it clear which object is being tested, especially in a test with a large setup. It also helps to avoid anti-patterns as it forces a test to have one SUT. The same standardization applies to what is expected with the name expected and results for any sut call results&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ This is in contrast to the actual entity name and actual result type i.e. deal. That approach means a lot of unique names and does not help in a large code base. As for the SUT, there is an understated benefit of immediately being able to identify what is the system under test, especially in a test with a large setup. This can also avoid anti-patterns as it forces a test to have one SUT. The same standardization applies to what is expected with the name &lt;code class=&quot;language-text&quot;&gt;expected&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;result&lt;/code&gt; for any sut call results.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the name &lt;code class=&quot;language-text&quot;&gt;result&lt;/code&gt;, for the result to be asserted in a test.\&lt;/p&gt;
&lt;p&gt;It is recommended to use the name result for the variable that holds the result of the system under test in your tests. This makes it clear what the variable represents and which variable is being asserted.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; abstract things out to keep arrange phase clean.&lt;/p&gt;
&lt;p&gt;It is a good practice to abstract things out to keep the arrange phase of your tests clean. This helps to reduce duplication and keep the tests concise. However, when doing this, make sure that it is still clear what is going on entirely from reading the test. It is very easy to introduce the mystery guest while doing this.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour naming tests in the format &lt;code class=&quot;language-text&quot;&gt;given then should&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;given when then should&lt;/code&gt;. Long test names are perfectly fine.&lt;/p&gt;
&lt;p&gt;The recommendation to name tests in the format given then should or given when then should is to make the intent of the test clear and to make it easy to understand what the test is doing. The given section sets up the initial conditions for the test, the when section describes the action being taken, and the then section describes the expected outcome.&lt;/p&gt;
&lt;p&gt;Using this naming convention can make it easier to write tests and can make it easier to read and understand the tests later on. The long test names may seem cumbersome, but they can make the tests more readable and self-documenting.&lt;/p&gt;
&lt;p&gt;For example, consider the following test name: &lt;code class=&quot;language-text&quot;&gt;GivenAListOfIntegers_WhenSortingInDescendingOrder_ThenShouldReturnSortedListInDescendingOrder&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This test name clearly states what the test is doing: it is given a list of integers, sorting them in descending order, and then it checks that the resulting list is sorted in descending order.&lt;/p&gt;
&lt;p&gt;Using this naming convention consistently throughout the project can make it easier for developers to find and understand tests, and can make the codebase more maintainable&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use tools that do not adhere to mocking best practices like &lt;code class=&quot;language-text&quot;&gt;NSubstitute&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It is important to use mocking tools that adhere to best practices, as otherwise, your tests may be unreliable and difficult to maintain. NSubstitute is one such tool that does not follow best practices, so it is recommended to avoid it.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; test the inner details of components, take a black box approach. Inner details should be able to change without necessarily affecting a consumer. When tests rely on these details they become brittle and high maintenance with minimal to no value added.&lt;/p&gt;
&lt;p&gt;It is important to take a black box approach to test components, as this ensures that your tests will be more resilient to changes in the implementation. If your tests rely on inner details, they may become brittle and difficult to maintain.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; aim for 100% code coverage instead aim for high-quality and low-effort tests. Focusing on code coverage regressions is however reasonable. Emphasis on this metric can lead to &lt;code class=&quot;language-text&quot;&gt;line hitter&lt;/code&gt; tests that developers create just to achieve a metric without really adding much value.&lt;/p&gt;
&lt;p&gt;While high code coverage is important, it should not be the sole focus of your testing efforts. Instead, aim for high-quality tests that are easy to write and maintain. Focusing too much on code coverage can lead to tests that are low-value and difficult to maintain&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO&lt;/strong&gt; not use the &lt;code class=&quot;language-text&quot;&gt;MemberData&lt;/code&gt; attribute for primitive types, only use this for complex types that cannot use &lt;code class=&quot;language-text&quot;&gt;InlineData&lt;/code&gt;. InlineData makes it easy to see the test and its test data easily, you lose this with a separate method for member data.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Theory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InlineData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InlineData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InlineData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InlineData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;){}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// IS BETTER THAN&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Theory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MemberData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TestData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;){}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; write tests with multiple responsibilities, instead a test should have a single focus. Multiple unrelated assertions are a red flag.&lt;/p&gt;
&lt;p&gt;When writing tests, it’s important to keep in mind that each test should have a single responsibility and focus. This means that multiple unrelated assertions within a single test should be avoided. When a test has multiple responsibilities, it becomes more difficult to understand and maintain and may lead to false positives or false negatives.&lt;/p&gt;
&lt;p&gt;Instead, tests should be written with a clear, single focus. This allows for better isolation of failures and makes it easier to diagnose and fix issues when they arise. It also helps to keep the tests readable and understandable, making it easier for other developers to understand what the test is testing and what the expected outcome is.&lt;/p&gt;
&lt;h2&gt;.NET&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of `AutoMoq to create instances of an object that have dependencies in tests.&lt;/p&gt;
&lt;p&gt;Data generators like Bogus can be very helpful for creating test data. Test data generation can be time-consuming, especially if the data needs to be complex or varied. By using a data generator, a developer can easily create a large amount of realistic data to use in testing. Paired builders are a common pattern for generating data that have relationships or dependencies between different objects. They can help create data that is more representative of real-world scenarios and make it easier to write tests that cover a variety of use cases.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The effort of mocking services is quite high given the typical number of dependencies&lt;/li&gt;
&lt;li&gt;Mocking service dependencies manually in tests creates fragile tests that will need updating each time those dependencies change. Ideally tests should change when behavior of interest changes.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Problem scenario:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ValueService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IJobService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ICache&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IServiceProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IClaimsPrincipalProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NullLoggerFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ILocalisedExceptionProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this case the only mock we care about is actually the data context and so the rest can be auto mocked.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;autoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AutoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetLoose&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RegisterInstance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;autoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ValueService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Additional cases:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;autoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AutoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetLoose&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// if you need a real instance of JobService, automock will transitively mock JobService&amp;#39;s deps as well&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RegisterType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;JobService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;As&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IJobService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RegisterInstance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// setup can be done on the mocks using Moq&amp;#39;s api as&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;autoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IJobService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Setup&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(...);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;autoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IJobService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Verify&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(...);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; replicate the folder structure of the project being tested in your tests. This makes it easy to navigate between the two and helps ensure that tests are placed in logical locations.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour creating test projects for each project being tested. This allows tests to be parallelized at a project level, which can help speed up test execution time. Using a single test project can create a bottleneck and slow down the testing process.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; name test files with suffix tests&lt;/p&gt;
&lt;p&gt;Naming test files with a suffix such as Tests help to indicate that the file is related to testing and makes it easier to find all test files in the codebase. The naming convention of using a Tests suffix is widely used and understood by developers in the .NET community, making it a best practice to follow.&lt;/p&gt;
&lt;p&gt;For example, suppose you have a class DictionaryExtensions in your production code that provides additional functionality for working with dictionaries. In that case, it would be a good practice to create a separate file DictionaryExtensionsTests.cs, which contains unit tests for the DictionaryExtensions class. This way, when you are navigating through the codebase, it is easy to identify and locate the tests for a given class or module.&lt;/p&gt;
&lt;p&gt;🎃 &lt;strong&gt;DO&lt;/strong&gt; be aware of a &lt;strong&gt;GOTCHA&lt;/strong&gt; with working with the EF core in-memory data context. This implementation chooses to enforce referential integrity for navigation properties. If you create an object that has a &lt;code class=&quot;language-text&quot;&gt;non-nullable&lt;/code&gt; navigation property and leaves this as null and then add it into the data context in your test, any attempt to read this back out will not return anything. All &lt;code class=&quot;language-text&quot;&gt;non-nullable&lt;/code&gt; navigation properties will have to be &lt;code class=&quot;language-text&quot;&gt;non-null&lt;/code&gt; as well for this to work. Quite the annoyance for tests but currently with no workaround.&lt;/p&gt;
&lt;p&gt;This is an important consideration when using the EF Core in-memory data context for testing. If you encounter this issue, you will need to make sure that all non-nullable navigation properties are set to non-null values.&lt;/p&gt;
&lt;h2&gt;Jest and React Testing Library&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; group related tests under a describe if multiple tests are in one file such as with tests for utils.&lt;/p&gt;
&lt;p&gt;When multiple tests are in one file, it’s a good idea to group them using the describe function. The describe function creates a block that groups together several related tests, making it easier to read and understand the test suite.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Utils&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;should do something&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// test code&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;should do something else&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// test code&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; name test files with suffix tests i.e &lt;code class=&quot;language-text&quot;&gt;utils.test.ts&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;breadCrumbs.test.tsx&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;src/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  utils.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  utils.test.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;  components/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    breadcrumbs.js&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;    breadcrumbs.test.js&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour data driven tests with &lt;code class=&quot;language-text&quot;&gt;test.each&lt;/code&gt; over duplicated tests&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1970&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1969&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1950&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;])(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;isDateBefore_1970 returns relevant boolean&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;isDateBefore_1970&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;🎃 When setting up a mock with jest.mock, ideally you may want to set up one of the properties based on a variable so that you can use the same value in your assertions. Jest will however fail the test complaining that mocks cannot access outside variables. This is in place to avoid dirty mocks, however, you can bypass this by simply naming the variables with the &lt;code class=&quot;language-text&quot;&gt;mock&lt;/code&gt; suffix i.e &lt;code class=&quot;language-text&quot;&gt;mockUser&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mockUnknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;#9E9E9E&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;jest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;../../redux/store&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getState&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RecursivePartial&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RootState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;app:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;statusColors:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;unknown:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mockUnknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;ReactTestUtils&lt;/code&gt;. Use &lt;code class=&quot;language-text&quot;&gt;React Testing Library&lt;/code&gt; which is designed to enable and encourage writing tests that use your components as the end users do. &lt;code class=&quot;language-text&quot;&gt;ReactTestUtils&lt;/code&gt; has features like mock elements, which do not simulate how a user will use the components and encourages
very bad testing approaches.&lt;/p&gt;
&lt;p&gt;ReactTestUtils is a utility library that was introduced early in the development of React. It provides various methods for testing React components. However, using ReactTestUtils is no longer recommended for testing React applications. The library encourages testing the internal implementation details of the components, rather than their behaviour, which can result in tests that are tightly coupled to the implementation and are therefore more brittle and difficult to maintain.&lt;/p&gt;
&lt;p&gt;Instead, the recommended approach for testing React components is to use React Testing Library. React Testing Library is a lightweight testing library that is designed to enable and encourage writing tests that use components as the end users do. Its API is designed to be intuitive and mirrors how users interact with components in the browser. For example, instead of directly accessing a component’s internal state and props, you interact with the component through its rendered output and the DOM nodes that it produces.&lt;/p&gt;
&lt;p&gt;React Testing Library is focused on testing the behaviour of the components, rather than their implementation details. This approach makes it easier to write tests that are maintainable and do not break as often. Additionally, the library provides a better developer experience and makes it easier to write tests that are expressive and easy to read.&lt;/p&gt;
&lt;h2&gt;Examples&lt;/h2&gt;
&lt;p&gt;Here are some examples to demonstrate some of these practices at play in unison.&lt;/p&gt;
&lt;h3&gt;.NET&lt;/h3&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Xunit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Moq&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AutoMoq&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Bogus&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;OrderServiceTests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Naming convention for test method is in the format of&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// given [scenario], when [action], then [expected outcome]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Fact&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GivenValidOrder_WhenSubmittingOrder_ThenOrderIsSavedAndConfirmationIsReturned&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Arrange&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;OrderService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Create a fake order using the Bogus data generator&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fakeOrder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Faker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RuleFor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Random&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RuleFor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CustomerName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FullName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RuleFor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ProductName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Commerce&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ProductName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RuleFor&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Quantity&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Random&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Generate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Use AutoMoq to create an instance of the OrderRepository with the required dependencies mocked&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mocker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AutoMoqer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mockRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mocker&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;OrderRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Set up the mock repository to return the fake order when the Save method is called&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mockRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Setup&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Save&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;It&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;IsAny&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;())).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Returns&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fakeOrder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Inject the mock repository into the SUT&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Repository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mockRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Act&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SubmitOrder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fakeOrder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Assert&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Check that the Save method was called on the mock repository with the correct argument&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mockRepository&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Verify&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Save&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fakeOrder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Times&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Once&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Check that the confirmation message is not empty and contains the order ID&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;IsNullOrEmpty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ConfirmationMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Contains&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fakeOrder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(), &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ConfirmationMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Check that the returned order is not null and has the same ID as the fake order&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NotNull&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Equal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fakeOrder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Order&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this test, we see the following best practices being applied:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The test method name follows the format given [scenario], when [action], then [expected outcome].&lt;/li&gt;
&lt;li&gt;The sut variable is used to clearly identify the System Under Test.&lt;/li&gt;
&lt;li&gt;The result variable is used to clearly identify the result of the action being tested.&lt;/li&gt;
&lt;li&gt;Mock objects are used to isolate the SUT from its dependencies.&lt;/li&gt;
&lt;li&gt;AutoMoq is used to make it easier to create mock objects with dependencies.&lt;/li&gt;
&lt;li&gt;The MemberData attribute is not used for primitive types in favor of InlineData.&lt;/li&gt;
&lt;li&gt;The test is kept focused with a single responsibility.&lt;/li&gt;
&lt;li&gt;The Fact attribute is used to mark the method as a test.&lt;/li&gt;
&lt;li&gt;The OrderServiceTests class follows the naming convention of adding Tests as a suffix to the class being tested.&lt;/li&gt;
&lt;li&gt;A shared data generator like Bogus is used to create fake orders for testing.&lt;/li&gt;
&lt;li&gt;The test code is kept organized with clear comments and whitespace.&lt;/li&gt;
&lt;li&gt;The &lt;code class=&quot;language-text&quot;&gt;Mock.Of&amp;lt;T&gt;&lt;/code&gt; factory method is used for mock objects with no additional setup required.&lt;/li&gt;
&lt;li&gt;The AutoMoq library is used to make tests more concise and easier to read.&lt;/li&gt;
&lt;li&gt;The result variable is used to clearly identify the result of the action being tested.&lt;/li&gt;
&lt;li&gt;The test file follows the naming convention of adding Tests as a suffix to the file being tested.&lt;/li&gt;
&lt;li&gt;The InlineData attribute is used to supply test data directly to the test method.&lt;/li&gt;
&lt;li&gt;The test method is kept focused with a single responsibility.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Import the function being tested&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formatName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;../utils&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Describe block for the group of tests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;describe&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;formatName function&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Single responsibility test case&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;should format a first and last name correctly&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Arrange&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;John&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Doe&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Act&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formattedName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;formatName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Assert using fluent assertions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formattedName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      .&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;string&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      .&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;and&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Doe, John&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Data driven tests with test.each&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;    firstName      | lastName        | expected&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;John&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;      | &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Doe&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;        | &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Doe, John&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Mary&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;      | &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Smith&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;      | &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Smith, Mary&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;James&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;     | &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Brown&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;      | &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Brown, James&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk8&quot;&gt;  `&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;should format $firstName $lastName correctly&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, ({ &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; }) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Arrange and Act&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formattedName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;formatName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Assert using fluent assertions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formattedName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Clear and concise test descriptions with given-when-then format&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;should capitalize the first letter of first and last names&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Arrange&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;john&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;doe&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Act&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formattedName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;formatName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;firstName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;lastName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Assert using fluent assertions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formattedName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Doe, John&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Descriptive naming for test files and functions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;should return an empty string if no parameters are passed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Arrange and Act&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formattedName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;formatName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Assert using fluent assertions&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formattedName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This test incorporates best practices such as using clear and concise test descriptions in the given-when-then format, having descriptive naming for test files and functions, using data-driven tests with test.each, using single-responsibility tests, and utilizing fluent assertions for more readable and maintainable test code.&lt;/p&gt;
&lt;h2&gt;Recommended reading&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;[xUnit Test Patterns(Refactoring Test Code)]&lt;a href=&quot;https://www.amazon.co.uk/xUnit-Test-Patterns-Refactoring-Signature/dp/0131495054&quot;&gt;https://www.amazon.co.uk/xUnit-Test-Patterns-Refactoring-Signature/dp/0131495054&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;https://www.amazon.co.uk/dp/1617296279/ref=as_li_tl?ie=UTF8&amp;#x26;linkCode=gs2&amp;#x26;linkId=bbc23e6697b3d4b1c78d3cffc3cc9f3a&amp;#x26;creativeASIN=1617296279&amp;#x26;tag=booksoncode-21&amp;#x26;creative=9325&amp;#x26;camp=1789&quot;&gt;Unit Testing:Principles, Practices and Patterns: Effective Testing Styles, Patterns, and Reliable Automation for Unit Testing, Mocking, and Integration Testing with Examples in C#&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.amazon.co.uk/dp/B0772S8R7Q/ref=as_li_tl?ie=UTF8&amp;#x26;linkCode=gs2&amp;#x26;linkId=8c075ed3114ab84c093b54c5a5353361&amp;#x26;creativeASIN=B0772S8R7Q&amp;#x26;tag=booksoncode-21&amp;#x26;creative=9325&amp;#x26;camp=1789&quot;&gt;C# and .NET Core Test-Driven Development: Dive into TDD to create flexible, maintainable, and production-ready .NET Core applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ &lt;a href=&quot;https://openai.com/blog/chatgpt/&quot;&gt;ChatGPT&lt;/a&gt; proved to be a very useful resource in proofreading the initial draft and researching more content.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Automating developer machine setup]]></title><description><![CDATA[Photo by charlesdeluvio on Unsplash Optimizing new developer machine setup This article will outline how I tackled an inefficiency around…]]></description><link>http://www.drunkonmonads.com/automate-dev-machine-setup/</link><guid isPermaLink="false">http://www.drunkonmonads.com/automate-dev-machine-setup/</guid><pubDate>Sat, 27 Aug 2022 09:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@charlesdeluvio?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;charlesdeluvio&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/pjAH2Ax4uWk?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Optimizing new developer machine setup&lt;/h1&gt;
&lt;p&gt;This article will outline how I tackled an inefficiency around the setting up of a new developer machine whenever someone new joins the team or someone gets a new machine. The existing process at the time was based on some text-based instructions that someone would have to follow manually, downloading applications and clicking through prompts, customizing tooling configuration, setting up tooling plugins, and manually verifying that all was set up well. This process had many flaws&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On updating the instructions it was difficult to verify that the update was correct and fits in with the rest of the steps&lt;/li&gt;
&lt;li&gt;The process was tedious and error-prone. It was easy to forget a step or struggle with out-to-date instructions or screenshots based on updates to tooling from the time the instructions were written.&lt;/li&gt;
&lt;li&gt;The process took time. While focusing on other onboarding processing and actioning the setup in between a new developer typically required a whole week to complete the setup.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As an engineering team we could do better and what we needed was to automate the process, but how? To best determine that we needed the criteria for automation and this was the requirement&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The automation should run within a time constraint of an hour considering an average internet connection for downloading required applications and SDKs&lt;/li&gt;
&lt;li&gt;Existing tooling should be leveraged. For example SDKs like node, dotnet, etc. ship with CLI tooling that could be utilized. I would further explore automation tools for setting up applications like Ansible, Chef, Chocolatey, etc.&lt;/li&gt;
&lt;li&gt;After machine setup, verification should be run to ensure that the setup was a success.&lt;/li&gt;
&lt;li&gt;The process should largely be customizable, giving developers flexibility over the tooling they use and how it is configured&lt;/li&gt;
&lt;li&gt;The setup should ideally have one entry point. A requirement to run multiple commands while better would still be counter to the goals&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From this, I further looked at what the automation details would be. Here are some examples of things a team may want to tackle:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Installing required tooling like SDKs, IDEs, etc&lt;/li&gt;
&lt;li&gt;Pulling down the base repository on the correct branch&lt;/li&gt;
&lt;li&gt;Installing code dependencies via tools like npm and NuGet&lt;/li&gt;
&lt;li&gt;Configuring git settings like autocrlf to team standard&lt;/li&gt;
&lt;li&gt;Setting up customized docker containers like Redis&lt;/li&gt;
&lt;li&gt;Validating required tool version specifics like .net, node, npm&lt;/li&gt;
&lt;li&gt;Validating the setup via executing certain steps in your repository, like restoring dependencies, linting, running tests, creating builds, etc.&lt;/li&gt;
&lt;li&gt;Running custom migrations like database migrations with DbUp or Entity Framework&lt;/li&gt;
&lt;li&gt;Verifying that all required tooling has been installed&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After thorough research, given my use case, I settled for the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Leverage Chocolatey for installing required software and plugins with a script that a developer can customize&lt;/li&gt;
&lt;li&gt;Leverage SDKs in use for further setups and verifications like dotnet and npm commands&lt;/li&gt;
&lt;li&gt;To ensure a single entry point while utilizing various tooling, a simple JavaScript script would be leveraged to orchestrate everything. Other scripting options like Powershell would have been viable, but JavaScript was specifically chosen as the skills to maintain this already existed in the team.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Here is an example chocolatey script &lt;code class=&quot;language-text&quot;&gt;setup-packages.config&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;?&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;xml&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;1.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt; encoding&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;utf-8&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;packages&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- mandatory --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;nodejs&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;18.8.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;dotnet-6.0-sdk&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;netfx-4.8-devpack&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;vscode&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;vscode-eslint&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;vscode-codespellchecker&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;visualstudio2022enterprise&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;visualstudio2022-workload-netweb&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;nswagstudio&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;docker-desktop&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;sql-server-2019&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;sql-server-management-studio&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;git&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;lens&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;kubernetes-helm&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;kubernetes-cli&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;awscli&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;eksctl&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;terraform&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;putty&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Optional, can substitute with own tools of choice --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;gitextensions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;vscode-vsliveshare&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;vscode-gitlens&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;vscode-csharp&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;googlechrome&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;lastpass-chrome&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;postman&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;chocolateygui&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;powertoys&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;7zip&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;paint.net&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;microsoft-windows-terminal&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;oh-my-posh&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;obsidian&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;devtoys&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;pulumi&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;mremoteng&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;packages&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here is an example implementation of an orchestration script &lt;code class=&quot;language-text&quot;&gt;setup.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;spawnSync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;child_process&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;versionValidators&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;executeInteractiveCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;} &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;./setup-module.mjs&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;process&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;rename&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;copyFile&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;existsSync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;fs&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;packagesJson&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;./package.json&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;engines&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;packagesJson&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;engines&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Warning&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;⚠ prerequisites:&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Chocolatey should be installed on this machine for this process to complete successfully&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;The docker daemon should be running&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;spawnSync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;pause&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;stdio:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;inherit&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shell:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;▶️ Starting repository verification&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;git --version&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Verifying if Git is installed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;▶️ Updating repository&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;git checkout develop&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Fetching latest changes&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;git pull&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Checking out develop branch&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;▶️ Configuring Git&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeInteractiveCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;git config --global core.autocrlf true&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Set core.autocrlf=true&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;▶️ Installing applications with chocolatey with no prompts. Check results.txt for status.&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  ),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;choco install setup-packages.config &amp;gt; result.txt -y&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Trigger chocolatey&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;▶️ Verifying installations&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;choco feature enable --name=&amp;#39;useEnhancedExitCodes&amp;#39; -y&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Enable chocolatey feature &amp;#39;&amp;#39; to get enhanced exit codes&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotnet --version&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Verifying if dotnet is installed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeInteractiveCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;nswag --versions&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Verifying if NSwag Studio is installed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;code --version&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Verifying if Visual Studio Code is installed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;choco find visualstudio2022enterprise -r -l&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Verifying if Visual Studio 2022 Enterprise is installed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;choco find visualstudio2022-workload-netweb -r -l&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Verifying if ASP.NET and web development workload for Visual Studio 2022 is installed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;choco find sql-server-2019 -r -l&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Verifying if Microsoft SQL Server 2019 Developer Edition is installed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;choco find sql-server-management-studio -r -l&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Verifying if Microsoft SQL Server Management Studio is installed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;choco find docker-desktop -r -l&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Verifying if Docker Desktop is installed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;https://www.docker.com/products/docker-desktop/&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;▶️  Setting up Custom Redis container&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;docker run --name dev-redis -p 6379:6379 -d redis&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Creating Redis container&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;▶️  Validating tooling versions&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;versionValidationErrors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;engines&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;engine&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;versionValidators&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;engine&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`Engine &amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;engine&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39; is unsupported.`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;versionValidators&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;engine&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;engines&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;engine&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  })&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Boolean&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;versionValidationErrors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Danger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;🚨 There were errors validating the compatibility of this computer:&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;versionValidationErrors&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;join&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;    &amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;▶️ Verifying .NET Solution&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotnet restore Sample.sln --force&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Restoring .net dependencies&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotnet build Sample.sln --no-restore&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Building .net solution&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotnet test Sample.sln  --no-build --no-restore&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Running .net tests&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;▶️ Updating database with DbUP&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;chdir&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Sample.DbUpgrader&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotnet run&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Executing DB Upgrader&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;▶️ Verifying Node Application&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;chdir&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;../Sample&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;▶️ Setting up Node Application developer .env file&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;existsSync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;.env&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Subtitle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Creating back up of existing .env file &amp;#39;.env.old&amp;#39;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;rename&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;.env&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;.env.old&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Subtitle&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;Creating new .env file from seed`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;copyFile&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;.env.seed&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;.env&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;npm install&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Installing Node Application dependencies&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;npm run test&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Running Node Application tests&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;npm run lint&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Running Node Application linting&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;npm run build&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Creating production Node Application build&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Success&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`✅  Verification completed successfully`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Supporting &lt;code class=&quot;language-text&quot;&gt;setup-module.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;javascript&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;spawnSync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;execSync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;child_process&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;process&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;semver&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;semver&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;versionErrorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;actual&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`This computer has &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;actual&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; installed, but &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; is required &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;    &amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Success:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;success&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Danger:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;danger&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;info&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Subtitle:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;subtitle&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ColoredMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;[MessageLevel.Success]:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;open:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\u&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;001b[32;1m&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;close:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\u&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;001b[0m&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;[MessageLevel.Warning]:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;open:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\u&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;001b[33;1m&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;close:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\u&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;001b[0m&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;[MessageLevel.Danger]:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;open:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\u&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;001b[31;1m&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;close:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\u&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;001b[0m&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;[MessageLevel.Info]:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;open:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\u&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;001b[36;1m&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;close:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\u&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;001b[0m&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;[MessageLevel.Subtitle]:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;open:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\u&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;001b[2;1m&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;close:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\u&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;001b[0m&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;validateVersion&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;▶️ Validating &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;actual&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;actual&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;execSync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`There was an error running the command &amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;:&lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;valid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;semver&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;satisfies&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;actual&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;valid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Success&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;✅  Success: Validating &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;valid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ? &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;versionErrorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;actual&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;modifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ColoredMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;modifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ColoredMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;modifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;close&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;versionValidators&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;dotnet&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;validateVersion&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotnet --version&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotnet&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;https://dotnet.microsoft.com/en-us/download&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;dotnet_format&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;validateVersion&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39; dotnet format --version&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;dotnet format&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`Please update npm by running &amp;#39;dotnet tool install -g dotnet-format --version &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;.*&amp;quot;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;node&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;validateVersion&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;node --version&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;node&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;https://nodejs.org&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;npm&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;validateVersion&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;npm --version&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;npm&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`Please update npm by running &amp;#39;npm install --global npm@&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;desired&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;executeCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ignoreError&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;▶️ &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;spawnSync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;stdio:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;inherit&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shell:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; !== &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;amp;&amp;amp; !&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ignoreError&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Danger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;🚨 Failure: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Success&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;✅  Success: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;executeInteractiveCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Info&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;▶️ &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;spawnSync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;command&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;shell:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; }).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;stderr&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toString&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Danger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;🚨 Failure: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;colorMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;MessageLevel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Success&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;indent&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;✅ Success: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk6&quot;&gt;\n\n&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;`&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;package.json&lt;/code&gt; for indicating setup dependencies and setting dependency version requirements via the &lt;code class=&quot;language-text&quot;&gt;engines&lt;/code&gt; with semantic versioning support.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Setup&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;description&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;repository&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;private&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;type&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;module&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;engines&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;dotnet&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;gt;=6&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;dotnet_format&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;gt;=6&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;node&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;18.8.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;npm&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;7.0.0&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;dependencies&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;semver&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;7.1.3&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This can be triggered with the command &lt;code class=&quot;language-text&quot;&gt;npm install; node --experimental-json-modules setup&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;This implementation met all the requirements criteria and in summary, was a success due to the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Process runs in just under an hour&lt;/li&gt;
&lt;li&gt;On update, this can be retested by spinning up a clean virtual machine and triggering the whole process&lt;/li&gt;
&lt;li&gt;Process is highly configurable, particularly the chocolatey configuration&lt;/li&gt;
&lt;li&gt;Verification can be run on demand to ensure that a developer machine meets requirements, particularly around things like SDK versions&lt;/li&gt;
&lt;li&gt;One would no longer have to wait weeks/months before using a certain tool or command to realize their machine is not correctly set up and lose hours trying to diagnose this. Verifications are now done on demand.&lt;/li&gt;
&lt;/ul&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk17 { color: #808080; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk6 { color: #D7BA7D; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Adopt AutoMock with Autofac and Moq]]></title><description><![CDATA[Photo by Sander Sammy on Unsplash Adopt AutoMock in dotnet tests for Autofac and Moq Context While the effort of manually mocking services…]]></description><link>http://www.drunkonmonads.com/adopt-automock/</link><guid isPermaLink="false">http://www.drunkonmonads.com/adopt-automock/</guid><pubDate>Sat, 27 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@sammywilliams?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Sander Sammy&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/q7ZlbWbDnYo?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Adopt AutoMock in dotnet tests for Autofac and Moq&lt;/h1&gt;
&lt;h2&gt;Context&lt;/h2&gt;
&lt;p&gt;While the effort of manually mocking services in .NET tests can be high, understanding the underlying mechanism of AutoMock can greatly reduce this complexity. AutoMock, when integrated with Autofac and Moq, not only simplifies the process but also provides a more intuitive approach to creating mocks. Here’s a deeper exploration of how AutoMock works&lt;/p&gt;
&lt;p&gt;Mocking service dependencies manually in tests creates fragile tests that will need updating each time those dependencies change. Ideally, tests should change when the behaviour of interest changes.&lt;/p&gt;
&lt;h2&gt;Problem scenario&lt;/h2&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SomeService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency3&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency4&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    );&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this hypothetical case, the only mock we care about is the data context and so the rest can be auto-mocked.&lt;/p&gt;
&lt;h2&gt;Recommendation&lt;/h2&gt;
&lt;p&gt;Adopt Autofac’s Moq helper &lt;a href=&quot;https://docs.autofac.org/en/latest/integration/moq.html&quot;&gt;automock&lt;/a&gt; as a way to create service instance SUTs (System Under Test). Unlike Autofixture this will not mock the SUT as well but will only locate the ctor and auto mock dependencies, maintaining trust in the SUT.&lt;/p&gt;
&lt;h3&gt;Application scenario&lt;/h3&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;autoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AutoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetLoose&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RegisterInstance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;autoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SomeService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now if &lt;code class=&quot;language-text&quot;&gt;SomeService&lt;/code&gt; were to have an additional dependency injected via the ctor which does not affect the behaviour we are testing, there is no need to update the test(s) as this will just get auto-mocked, ideally what we would have done manually anyway.&lt;/p&gt;
&lt;h3&gt;Additional cases&lt;/h3&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;autoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AutoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetLoose&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;//If you need a real instance of a dependency, auto mock will transitively mock the concrete implementation&amp;#39;s dependencies as well&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RegisterType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Dependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;As&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;RegisterInstance&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;//Setup and verifications can be done on the mocks using Moq&amp;#39;s API as&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;autoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Setup&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(...);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;autoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Verify&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(...);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A great thing about Auto mock is that it exposes the Moq API, meaning everything else is working with Moq.&lt;/p&gt;
&lt;h2&gt;Benefits&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Over time the dependency list can grow and it is quite cumbersome to have to modify tests to add new mocks&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Quite often most of the mocks do not require setup so you do not need to explicitly create the mock, it can be auto-created&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The code can be made more succinct and easier to read&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Often when a service is updated to add a new dependency, this indicates new behaviour and likely means you would add new tests, not modify existing ones. With this approach, you do not have to update the tests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Is Onboarded To Portal&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Adopt run books]]></title><description><![CDATA[Photo by Calle Macarone on Unsplash Adopt run books A Run Book / Operations Manual for known maintenance scenarios. These should act as a…]]></description><link>http://www.drunkonmonads.com/adopt-run-books/</link><guid isPermaLink="false">http://www.drunkonmonads.com/adopt-run-books/</guid><pubDate>Sat, 27 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/ja/@callemac?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Calle Macarone&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/15wIddvL5dU?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Adopt run books&lt;/h1&gt;
&lt;p&gt;A Run Book / Operations Manual for known maintenance scenarios. These should act as a technical support knowledge base. Run books, often underutilized, serve as a beacon of clarity and order in this chaotic landscape. They are comprehensive, step-by-step guides that detail the processes and actions necessary for handling routine operational tasks and resolving incidents.&lt;/p&gt;
&lt;p&gt;Example scenarios include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Routine maintenance like database backups&lt;/li&gt;
&lt;li&gt;Incident response like a security breach&lt;/li&gt;
&lt;li&gt;Software deployments&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Any known manual tasks or issue remedies should be documented as a run book including any scripts used to automate technical workflows or investigations of production issues.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Please keep these run books up to date. If you run through one and notice something different or require additional steps please do account for this. If you solve a new technical issue do document this as a run book. This avoids solving the same problems over and over.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Best Practices&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Ensure each step in the run book is clearly described and easy to follow. Avoid jargon and overly technical language unless absolutely necessary.&lt;/li&gt;
&lt;li&gt;Keep run books up-to-date with the latest procedures and changes in the infrastructure. Outdated run books can lead to ineffective or harmful actions.&lt;/li&gt;
&lt;li&gt;Regularly test the procedures in your run books to ensure they work as expected. This is especially crucial for critical incident response run books.&lt;/li&gt;
&lt;li&gt;Encourage team members to provide feedback on the run books based on their experiences. Continuous improvement is key to maintaining effective run books.&lt;/li&gt;
&lt;li&gt;Incorporate run books into training programs for new staff to ensure they are familiar with established procedures and protocols.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By adopting these practices, organizations can maximize the effectiveness of their run books, leading to more efficient and reliable operations and incident management.&lt;/p&gt;
&lt;h2&gt;Template&lt;/h2&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;markdown&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;# Description&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;## Situation&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;What is the situation that this run book addresses?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;## Remedy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;What steps need to be taken to remedy this?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Example&lt;/h2&gt;
&lt;h1&gt;How to assume an AWS IAM role via the CLI&lt;/h1&gt;
&lt;h2&gt;You need to assume a role from the AWS CLI&lt;/h2&gt;
&lt;h2&gt;Situation&lt;/h2&gt;
&lt;p&gt;Assume/Impersonate a role that has the rights you desire using &lt;code class=&quot;language-text&quot;&gt;aws sts&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;assume-role&lt;/code&gt; command&lt;/p&gt;
&lt;h2&gt;Solution&lt;/h2&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;aws sts assume-role --role-arn &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;arn:aws:iam::[Account Id]:role/[Role Name]&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --role-session-name [Session Name]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Depending on your workflow, ensure that the &lt;code class=&quot;language-text&quot;&gt;AccessKeyId&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;SecretAccessKey&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;SessionToken&lt;/code&gt; output from that command are stored where they need to be. Also, ensure that the region is set to the desired target. A simple approach is to create a new section in the credentials file and mark that as the default with the required values.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;[default]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;aws_access_key_id = [Access Key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;aws_secret_access_key = [Secret Key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On completion, a session token will be added to the credentials file:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;[default]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;aws_access_key_id = [Access Key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;aws_secret_access_key = [Secret Key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;aws_session_token=[Security Token]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Assuming a role provides a short-lived token, if you suddenly lose access again, check that the token has not expired. In which case you will need to assume the role again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtkb { font-weight: bold; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[How to assume an AWS IAM role via the CLI]]></title><description><![CDATA[Photo by engin akyurt on Unsplash Assuming an AWS IAM role via the CLI is a crucial part of managing your AWS resources securely. This guide…]]></description><link>http://www.drunkonmonads.com/assume-aws-iam-role-cli/</link><guid isPermaLink="false">http://www.drunkonmonads.com/assume-aws-iam-role-cli/</guid><pubDate>Sat, 27 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/pt-br/@enginakyurt?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;engin akyurt&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/8sM2SsANvKk?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Assuming an AWS IAM role via the CLI is a crucial part of managing your AWS resources securely. This guide will walk you through the process, step by step, and provide best practices to ensure a smooth experience.&lt;/p&gt;
&lt;h2&gt;Approach&lt;/h2&gt;
&lt;p&gt;Assume/Impersonate a role that has rights you desire using &lt;code class=&quot;language-text&quot;&gt;aws sts&lt;/code&gt; &lt;code class=&quot;language-text&quot;&gt;assume-role&lt;/code&gt; command&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;aws sts assume-role --role-arn &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;arn:aws:iam::[Account Id]:role/[Role Name]&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; --role-session-name [Session Name]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Depending on your workflow, ensure that the &lt;code class=&quot;language-text&quot;&gt;AccessKeyId&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;SecretAccessKey&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;SessionToken&lt;/code&gt; output from that command are stored where they need to be securely. Also, ensure that the region is set to the desired target. A simple approach is to create a new section in the credentials file and mark that as the default with the required values.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;[default]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;aws_access_key_id = [Access Key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;aws_secret_access_key = [Secret Key]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On completion, a session token will be added to the credentials file:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;[default]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;aws_access_key_id = [Access Key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;aws_secret_access_key = [Secret Key]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;aws_session_token=[Security Token]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ It’s important to note that assuming a role provides a short-lived token. If you suddenly lose access, check that the token has not expired, in which case you will need to assume the role again.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Usage scenarios&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cross-Account Access: Assume a role in another AWS account to access resources securely.&lt;/li&gt;
&lt;li&gt;Temporary Permissions: Provide temporary elevated permissions to users or services without sharing long-term access keys.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Assuming an AWS IAM role via the CLI is a powerful way to enhance the security of your AWS resources. By following these steps and best practices, you can efficiently manage your AWS access and permissions.&lt;/p&gt;
&lt;p&gt;For more detailed information and advanced use cases, refer to the official AWS IAM documentation.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Resolve Cryptographic Exceptions in IIS]]></title><description><![CDATA[Photo by Etienne Girardet on Unsplash Resolve Cryptographic Exception in IIS Situation An IIS deployed application is throwing a  with the…]]></description><link>http://www.drunkonmonads.com/cyrptographic-exception-in-iis/</link><guid isPermaLink="false">http://www.drunkonmonads.com/cyrptographic-exception-in-iis/</guid><pubDate>Sat, 27 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/fr/@etiennegirardet?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Etienne Girardet&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/DOKXRZPyQk0?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Resolve Cryptographic Exception in IIS&lt;/h1&gt;
&lt;h2&gt;Situation&lt;/h2&gt;
&lt;p&gt;An IIS deployed application is throwing a &lt;code class=&quot;language-text&quot;&gt;CryptographicException&lt;/code&gt; with the message &lt;code class=&quot;language-text&quot;&gt;System cannot find the specified file&lt;/code&gt;. Not a very useful message now is it?!&lt;/p&gt;
&lt;h2&gt;Remedy&lt;/h2&gt;
&lt;p&gt;This is most likely because the Windows Cryptographic Service Provider was trying to store or load a key for a certificate in the user store, and since a profile was not available, a cryptographic context was not available. This means the Process model has the &lt;code class=&quot;language-text&quot;&gt;Load User Profile&lt;/code&gt; set to false.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ The Load User Profile setting only applies to user accounts. Service Accounts like NETWORK SERVICE and ApplicationPoolIdentity have special handling.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;What exactly happens when I set Load User Profile in the IIS pool?&lt;/h3&gt;
&lt;p&gt;The user profile is loaded. This includes their cryptographic store, environment variables such as %TEMP%, and other ones.&lt;/p&gt;
&lt;h3&gt;To enable the setting&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go to the IIS Manager&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to the application pool instance&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click on Advanced settings&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Under the Process model, set Load User Profile to true&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Recycle the application pool and restart the linked web application for changes to reflect&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Adopting decision records]]></title><description><![CDATA[Photo by Maksym Kaharlytskyi on Unsplash Architecture Decision Records (ADRs) An Architecture Decision Record (ADR) is a software design…]]></description><link>http://www.drunkonmonads.com/decision-records/</link><guid isPermaLink="false">http://www.drunkonmonads.com/decision-records/</guid><pubDate>Sat, 27 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@qwitka?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Maksym Kaharlytskyi&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/Q9y3LRuuxmg?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Architecture Decision Records (ADRs)&lt;/h1&gt;
&lt;p&gt;An Architecture Decision Record (ADR) is a software design choice documentation that addresses a functional or non-functional requirement that is architecturally significant.&lt;/p&gt;
&lt;p&gt;Having this record-keeping allows the team to easily go back in time to understand the current status and be better able to pivot with complete knowledge. These prove very useful for new joiners as well. Another key thing is that when the team decides on something and someone is tasked with putting it down as a record, often that could identify gaps or misalignment and allow addressing this early on particularly when examples are involved.&lt;/p&gt;
&lt;h2&gt;Example&lt;/h2&gt;
&lt;hr&gt;
&lt;h1&gt;Adopt SQL Temporal Tables for time travel&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Created: 2023-01-01&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Updated: 2023-01-05&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Participants: Entire Tech Team&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Status&lt;/h2&gt;
&lt;p&gt;Accepted&lt;/p&gt;
&lt;h2&gt;Context&lt;/h2&gt;
&lt;p&gt;We are building an Analytics database that needs to keep track of historical data, and we need to decide on the best way to implement this feature.&lt;/p&gt;
&lt;h2&gt;Alternatives&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;…&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SQL Temporal Tables: This approach involves using the built-in SQL temporal table feature to automatically track the history of a table. This approach allows for easy querying of historical data and does not require additional storage as the history is stored in the same table as the current data.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Decision&lt;/h2&gt;
&lt;p&gt;We will use the SQL Temporal Tables approach for tracking history.&lt;/p&gt;
&lt;h2&gt;Reasoning&lt;/h2&gt;
&lt;p&gt;SQL Temporal Tables allow for easy querying of historical data. It also allows storing the history of a table transparently and is easy to use.&lt;/p&gt;
&lt;h3&gt;Pros&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Temporal tables allow for easy tracking and querying of historical data.&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Cons&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Temporal tables can add complexity to a database schema.&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2&gt;Authoring recommendations&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that the records are immutable. The decisions made in a previously published ADR should not be altered in a way that changes the decision, a new record should be made in the interest of maintaining the history.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that each record is specific to one decision only.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that all decisions are consistent with other team and organization agreed-upon principles and standards.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; reference other detailed documentation and supporting artefacts to avoid duplications.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that you document a clear argument as this is as important as the decision. Outline the position, including things like implementation cost, ownership cost, resource requirements, etc.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; follow a minimalist approach and document only the issues that need addressing or attention.&lt;/p&gt;
&lt;h2&gt;Template&lt;/h2&gt;
&lt;hr&gt;
&lt;h1&gt;NUMBER - Title&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Created: [YYYY-MM-DD] when the decision was created&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Updated: [YYYY-MM-DD] when the decision was last updated&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Participants: [list involved participants/team]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Status&lt;/h2&gt;
&lt;p&gt;Proposed | Rejected | Accepted | Deprecated | … | Superseded by [Another Run Book Link]&lt;/p&gt;
&lt;h2&gt;Context&lt;/h2&gt;
&lt;p&gt;Describe the context and problem statement, e.g., in free form using two to three sentences. You may want to articulate the problem in form of a question&lt;/p&gt;
&lt;h2&gt;Decision&lt;/h2&gt;
&lt;p&gt;This is the decision that was made if any alternatives were considered, list them here&lt;/p&gt;
&lt;h2&gt;Consequence&lt;/h2&gt;
&lt;h2&gt;This is the consequence of the decision&lt;/h2&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In summary, ADRs are instrumental in maintaining a clear and accessible record of architectural decisions, aiding in team alignment, retrospective analysis, and onboarding new members.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Reason for Outage tracking]]></title><description><![CDATA[Photo by Антон Дмитриев on Unsplash Reason For Outage (RFO) tracking An RFO (Reason for Outage) is a body of knowledge for tracking known…]]></description><link>http://www.drunkonmonads.com/rfo-tracking/</link><guid isPermaLink="false">http://www.drunkonmonads.com/rfo-tracking/</guid><pubDate>Sat, 27 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@ehmitrich?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Антон Дмитриев&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/y4aUBTWgzgQ?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Reason For Outage (RFO) tracking&lt;/h1&gt;
&lt;p&gt;An RFO (Reason for Outage) is a body of knowledge for tracking known outages to learn from and to use as a reference when going back in time. This creates an actionable history of things that go wrong in production environments and can help in decision-making and resolution of potential issues.&lt;/p&gt;
&lt;p&gt;Outages include&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Resources that become unavailable. This could be due to many issues like network, infrastructure, faulty applications&lt;/li&gt;
&lt;li&gt;Failed deployments&lt;/li&gt;
&lt;li&gt;Manual application restarts necessitated by something going wrong&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Outages do not include&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Maintenance application/infrastructure restarts that are expected&lt;/li&gt;
&lt;li&gt;Application downtimes due to deployments. This is not ideal however and can be avoided by adopting a different deployment strategy.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;markdown&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;# Reason for Outage&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;# Outage&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;ISO Date&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Description&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Resolution&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;markdown&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;# Reason for Outage&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4 mtkb&quot;&gt;# Surge in application Kubernetes pods restart&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;2022-08-27&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;There was an increase in the number of Kubernetes pod restarts starting at ... and flagged by DataDog at ... . See the screenshot below.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;The surge in pod restarts was due to a faulty configuration of ... that led to an increase in memory usage and eventually some Out of Memory Exceptions that were resulting in pod restarts. See details on the ticket ... about the misconfiguration and resolution.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;DataDog monitors were also updated by applying ... to ensure that when something like this happens we will be notified within a shorter window.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtkb { font-weight: bold; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Secure AWS instance metadata]]></title><description><![CDATA[Photo by regularguy.eth on Unsplash Secure AWS EC2 instance metadata Instance metadata is data about your instance that you can use to…]]></description><link>http://www.drunkonmonads.com/secure-aws-instance-metadata/</link><guid isPermaLink="false">http://www.drunkonmonads.com/secure-aws-instance-metadata/</guid><pubDate>Sat, 27 Aug 2022 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@moneyphotos?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;regularguy.eth&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/-o90yRQoXAM?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Secure AWS EC2 instance metadata&lt;/h1&gt;
&lt;p&gt;Instance metadata is data about your instance that you can use to configure or manage the running instance. Instance metadata is divided into &lt;a href=&quot;https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-data-categories.html&quot;&gt;categories&lt;/a&gt;, for example, host name, events, and security groups. As a practice, the exposing of data about an instance via an internal endpoint this is not limited to just AWS. A Cloud Metadata Attack attempts to abuse a misconfigured web server in order to access the instance metadata maintained by cloud service providers such as AWS, GCP, and Azure. All of these providers provide metadata via an internal unrouteable IP address &lt;code class=&quot;language-text&quot;&gt;169.254.169.254&lt;/code&gt; - this can be exposed by incorrectly configured web servers and accessed by using this IP address in the Host header field. This makes instance metadata security-sensitive given that if attackers get access to this they have specifics about your instances such as OS, security groups etc. that could allow for more targeted attacks with a higher success rate.&lt;/p&gt;
&lt;h2&gt;Solution&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Do not trust user data in web server configuration. For example in &lt;a href=&quot;https://www.nginx.com/blog/trust-no-one-perils-of-trusting-user-input/&quot;&gt;NGINX configs the $host variable which is set from the ‘Host’ header can be controlled by an attacker&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Disable instance metadata. This is not always an option, for example, in AWS there are services such as Systems Manager that rely on this metadata to correctly identify instances.&lt;/li&gt;
&lt;li&gt;Secure the instance metadata. That is what we shall be focusing on.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Secure instance metadata&lt;/h2&gt;
&lt;p&gt;This change cannot be done in the AWS console and requires the use of the AWS CLI. Impersonate a role that has the rights to make this change if required or attain user login from the CLI.&lt;/p&gt;
&lt;p&gt;Run a command to update the instance metadata as required. For example to enable the HTTP endpoint on a given instance:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;aws ec2 modify-instance-metadata-options --instance-id [INSTANCE_ID] --http-endpoint enabled&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ It is desirable to keep the instance metadata enabled as this is required by various AWS services including Systems Manager which we require for automated scanning and patching of EC2 instances. This means the &lt;code class=&quot;language-text&quot;&gt;http-endpoint&lt;/code&gt; flag should always be set to &lt;code class=&quot;language-text&quot;&gt;enabled&lt;/code&gt;. To enforce security however, we set the &lt;code class=&quot;language-text&quot;&gt;http-tokens&lt;/code&gt; option to &lt;code class=&quot;language-text&quot;&gt;required&lt;/code&gt; which enforces sending a signed token header with any instance metadata retrieval request and hence requires an IAM role which is harder to be exploited. Additionally the &lt;code class=&quot;language-text&quot;&gt;http-put-response-hop-limit&lt;/code&gt; is also set to &lt;code class=&quot;language-text&quot;&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;aws ec2 modify-instance-metadata-options --instance-id [INSTANCE_ID] --http-endpoint enabled --http-tokens required --http-put-response-hop-limit 1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get the status of a given instance run the following command&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;aws ec2 describe-instances --instance-id [Instance ID]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# this return a lot of data so preferable pipe to file to view easily&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;aws ec2 describe-instances --instance-id [Instance ID] &amp;gt; result.txt&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[C# Standards and Best Practices]]></title><description><![CDATA[Photo by Gabriel Vasiliu on Unsplash C# Standards and Best Practice A list of recommendations around working with C# and dotnet that can…]]></description><link>http://www.drunkonmonads.com/c-sharp-standards/</link><guid isPermaLink="false">http://www.drunkonmonads.com/c-sharp-standards/</guid><pubDate>Wed, 24 Aug 2022 19:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@gabimedia?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Gabriel Vasiliu&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/K-dqI8-cUMQ?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;C# Standards and Best Practice&lt;/h1&gt;
&lt;p&gt;A list of recommendations around working with C# and dotnet that can potentially be adopted by a team as standards. I highly recommend teams should have very clear and explicit standards documented, similar to the one below that is agreed upon and enforced.&lt;/p&gt;
&lt;p&gt;There are multiple ways to enforce standards&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pull request verification manual checks&lt;/li&gt;
&lt;li&gt;Automated checks like linters, Roslyn analyzers, etc.&lt;/li&gt;
&lt;li&gt;Code scanning tools like Sonar&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of &lt;code class=&quot;language-text&quot;&gt;EditorConfig&lt;/code&gt; with .NET and leveraging Roslyn analyzers. This brings a powerful combination that enforces coding standards and promotes consistent code quality across your projects.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Consistent Coding Standards&lt;/strong&gt;: EditorConfig provides a standardized format to define and enforce coding conventions such as indentation style, line endings, and whitespace usage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Team Collaboration and Onboarding&lt;/strong&gt;: When multiple developers work on a project, maintaining a shared understanding of coding standards becomes critical. EditorConfig allows you to specify and communicate these standards effectively, promoting collaboration and reducing time spent on code reviews. New team members can quickly adapt to the project’s coding style by simply configuring their editor to read the shared EditorConfig file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Automated Standards Validation&lt;/strong&gt;: Integrating EditorConfig with Roslyn analyzers takes consistency to the next level. Roslyn analyzers are powerful static analysis tools that can automatically validate your code against a set of rules defined in the EditorConfig file.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Customizable and Extensible&lt;/strong&gt;: Both EditorConfig and Roslyn analyzers are highly customizable to fit your project’s unique needs. Additionally, you can create custom analyzers to enforce project-specific guidelines, ensuring that your codebase adheres to your organization’s best practices.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Cross-Editor and Cross-Platform Support&lt;/strong&gt;: EditorConfig is supported by a wide range of popular editors, including Visual Studio, Visual Studio Code, and JetBrains IDEs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;bash&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;root = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[*]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;guidelines = 120&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# All files&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[*]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;indent_style = space&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# cancellation tokens must be forwarded to methods that accept them&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.CA2016.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# cancellation tokens must come last in method signatures&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;dotnet_diagnostic.CA1068.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;On creating an &lt;code class=&quot;language-text&quot;&gt;editorconfig&lt;/code&gt; for the first time using Visual Studio, it will infer some rules by analyzing the code, which gives a good head start.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Working with secrets&lt;/h1&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; store secrets within the source code or source code directories. These can be accidentally committed by introducing surface area for leakage. Make use of user secrets that are managed outside of a repository.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ The Secret Manager tool doesn’t encrypt the stored secrets and shouldn’t be treated as a trusted store. It’s for development purposes only. The keys and values are stored in a JSON configuration file in the user profile directory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use production secrets for non-production environments. These should be considered highly sensitive and isolated. For example, do not use the same storage location for development purposes as production and share access keys even if you isolate them in other ways like folders, etc.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; deploy secrets with an application, ideally these should be accessible through a controlled means like environment variables. This principle is particularly important if you adhere to the [12 Factor App](&lt;a href=&quot;https://12factor.net/&quot;&gt;The Twelve-Factor App (12factor.net)&lt;/a&gt;) way of managing an application.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use the &lt;code class=&quot;language-text&quot;&gt;:&lt;/code&gt; character when working with secrets in flat files to create a hierarchy, make use of the &lt;code class=&quot;language-text&quot;&gt;__&lt;/code&gt; sequence which is supported by all platforms.&lt;/p&gt;
&lt;h1&gt;Projects&lt;/h1&gt;
&lt;h2&gt;Structure&lt;/h2&gt;
&lt;p&gt;Do adhere to a strict structure of managing projects and consistently/religiously apply this.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that projects are located in &lt;code class=&quot;language-text&quot;&gt;/src&lt;/code&gt; and their tests are located in &lt;code class=&quot;language-text&quot;&gt;/test&lt;/code&gt;, not just as projects in VS Solution Explorer but including the file structure. In addition to a clean separation, the projects and tests have separate &lt;code class=&quot;language-text&quot;&gt;Directory.Build.prop&lt;/code&gt; files and &lt;code class=&quot;language-text&quot;&gt;.editorconfig&lt;/code&gt; files. This will decouple rules around code from tests, meaning for instance that Roslyn’s analysis is specific to each group and dependencies are managed differently.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;Consider&lt;/strong&gt; adding changes that affect multiple projects and need to be consolidated such as project version numbers and dependencies to &lt;code class=&quot;language-text&quot;&gt;Directory.Build.props&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;Directory.Build.targets&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;directory.build.props&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This file is used to define project properties and configuration settings. It is primarily used to customize the build process at the project level. You would use &lt;code class=&quot;language-text&quot;&gt;directory.build.props&lt;/code&gt; when you want to define common properties, references, or other configuration settings that apply to multiple projects within a directory or solution. For example, you can use &lt;code class=&quot;language-text&quot;&gt;directory.build.props&lt;/code&gt; to set the default output directory, set the target framework, define preprocessor symbols, specify common package references, or enable/disable build features across multiple projects. This file helps ensure consistency and reduces duplication in the build configuration.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Set the target framework version for all projects --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;net5.0&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Set some default usings --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;System&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;System.Linq&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;System.Threading&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;System.Threading.Tasks&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;System.Collections.Generic&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Custom Build Configuration --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Custom properties specific to the build configuration --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;OutputPath&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;$(SolutionDir)Output\$(Configuration)\&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;OutputPath&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;DefineConstants&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;DEBUG;TRACE&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;DefineConstants&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Specify default package references for all projects --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Newtonsoft.Json&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;13.0.1&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Custom Build Features --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Enable/Disable custom build features --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Optimize&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Optimize&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;TreatWarningsAsErrors&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;TreatWarningsAsErrors&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Additional Properties --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Additional project properties --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;MyCustomProperty&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;Custom Value&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;MyCustomProperty&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you have multiple layers of &lt;code class=&quot;language-text&quot;&gt;director.build.props&lt;/code&gt; files, you can inherit from a base file, for example, if you have one at the solution root and a more specific one in the tests folder root that only applies to tests, you can do the following:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Inherit from one in solution root --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;$([MSBuild]::GetPathOfFileAbove(&amp;#39;Directory.Build.props&amp;#39;, &amp;#39;$(MSBuildThisFileDirectory)../&amp;#39;))&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;FluentAssertions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;6.11.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Microsoft.NET.Test.SDK&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;17.6.2&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Xunit&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;2.4.2&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Xunit.Runner.VisualStudio&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;2.4.5&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Moq&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;4.18.4&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Moq.AutoMock&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;3.5.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Moq&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Xunit&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Moq.AutoMock&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;directory.build.targets&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This file is used to customize the build process by adding or overriding build targets. It allows you to insert custom build steps at specific points in the build process or modify the behaviour of existing build targets.
You would use &lt;code class=&quot;language-text&quot;&gt;directory.build.targets&lt;/code&gt; when you need to perform additional actions during the build, such as code generation, resource updates, or file copying. You can also use it to override or extend the behaviour of existing build targets provided by the default build process.&lt;/p&gt;
&lt;p&gt;For example, you can add a custom target to run a script before or after the build, modify the output files, or inject additional dependencies into the build process.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Custom Build Step --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;CustomBuildStep&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;BeforeTargets&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Build&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Add custom build step to run before the build --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Exec&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Command&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;echo Running custom build step...&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Copy Additional Files --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;CopyAdditionalFiles&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;AfterTargets&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;AfterBuild&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;&amp;lt;!-- Copy additional files after the build completes --&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Copy&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;SourceFiles&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;$(ProjectDir)ExtraFiles\*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DestinationFolder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;$(OutputPath)&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Target&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Logging&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of &lt;code class=&quot;language-text&quot;&gt;Microsoft.Extensions.Logging&lt;/code&gt; as the primary API for logging. Do not use SDKs like &lt;code class=&quot;language-text&quot;&gt;Serilog&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;ApplicationInsights&lt;/code&gt; for this. 3rd party tooling can be changed at any time and in that case, should only be used for bootstrapping or wrapped around to avoid work on moving to something different.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ For example you can adopt the use of &lt;code class=&quot;language-text&quot;&gt;Serilog&lt;/code&gt; for logger bootstrapping due to the power and flexibility it has with the supported sinks over &lt;code class=&quot;language-text&quot;&gt;Microsoft.Extension.Logging&lt;/code&gt;. Its use should then be limited only to that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of log scopes (log context) at all times. As an example, if a controller action has access to a correlation id for something that is being operated on, if this is added to the context and multiple call chains down the line some exception occurs and is captured there + logged, it will contain that correlation id which is very useful.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BeginScope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CorrelationId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;quot;] = &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// other method calls&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;BeginScope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&amp;quot;{&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Operation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;} &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;running&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;department&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Department&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&amp;quot;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;operationName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;departmentName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// other method calls&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Do ensure that all context follows the &lt;code class=&quot;language-text&quot;&gt;key:value&lt;/code&gt; pair pattern. Scopes that only have values can be confusing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Do consider making use of some form of middleware to extract and include common information that is useful in logs via the log context.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that log messages are as detailed and specific as possible.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; carefully consider the design of generic implementations of things like Job runners that are meant to be extended with additional implementations. These should have hooks to allow for adding generic logging or metrics tracking like timing operations in a single place as opposed to all implementations.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;How ASP.NET WEB API middleware works is a good example of a hook that allows for intercepting a given pipeline. A more general approach would be to require implementations that override a virtual base class method that can be used to apply such a hook. The same scenario handled with implementing an abstract class would not offer such functionality.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; pay close attention to the data that is exposed in logs, especially when setting log scopes with object destructuring to avoid leaking sensitive information. Any secrets like passwords/API keys (even when encrypted) and personally identifiable information like email addresses should not end up in logs.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; pay close attention to the size of log or metrics payloads. Overly large data payloads should be avoided. As a safety net where possible set the config of your logger such as &lt;code class=&quot;language-text&quot;&gt;Serilog&lt;/code&gt; to limit the depth of destructuring and cap the string length, but care is still required as this can be bypassed with context and scopes.&lt;/p&gt;
&lt;p&gt;Serilog example&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Serilog&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Using&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Serilog.Sinks.Console&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Destructure&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;ToMaximumDepth&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Args&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;maximumDestructuringDepth&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;ToMaximumStringLength&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Args&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;maximumStringLength&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that all logs are emitted to the console as structured and compact JSON logs. This follows the &lt;code class=&quot;language-text&quot;&gt;12 factor Apps&lt;/code&gt; approach to logging and is ideal for log targets to analyze the logs.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; treat logging and metrics as auxiliary concerns, meaning they should not impact functionality i.e. by causing bottlenecks or unhandled exceptions. While you would not wrap log call around try/catch block you need to apply defensive coding esp. around the risk of null reference issues.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Logging to the console is one way to avoid bottlenecks and have agents scrape the logs and worry about shipping them. For deployments where file-based logging is required, in those cases find an approach that does not create a synchronous bottleneck on logging to IO. For example with &lt;code class=&quot;language-text&quot;&gt;Serilog&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Serilog.Sinks.File&lt;/code&gt; sink can be configured to be wrapped around &lt;code class=&quot;language-text&quot;&gt;Serilog.Sinks.Async&lt;/code&gt; to reduce the overhead of logging calls by delegating work to a background thread as files are prone to I/O bottlenecks.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Serilog Example&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Serilog&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Async&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Args&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;configure&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Name&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;File&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;Args&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;path&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Application.log&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;rollingInterval&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Day&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;rollOnFileSizeLimit&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;retainedFileCountLimit&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;formatter&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Serilog.Formatting.Compact.CompactJsonFormatter, Serilog.Formatting.Compact&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          ]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; bootstrap the logging and the application annotations (read by scrapping agents) in a way that ensures that at minimum logs/metrics are identifiable with what application sent the log, the level of the log, the source of the log (class/controller/action name, etc.), the deployment stack (i.e. k8s namespace) and other information like application region that are applicable. Additional information such as request hostname, accessed resource IDs, etc. can further enrich logs.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; tag logs that are not useful except in exceptional cases as &lt;code class=&quot;language-text&quot;&gt;Debug&lt;/code&gt; so that these by default are not shipped out to the sink. In the event of an exceptional need for these logs then the configuration can be updated to include &lt;code class=&quot;language-text&quot;&gt;Debug&lt;/code&gt; logs. Examples of these kinds of logs are generated SQL queries from EF Core and transactional logs such as indicating the start of a job.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; ship logs directly to a log target. In the case of docker-based deployments like Kubernetes, a sidecar agent is responsible for scrapping pod logs and ensuring that they get shipped out to the sink and any other heavy lifting like dealing with network issues, buffering, etc.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ A twelve-factor app never concerns itself with routing or storage of its output stream. It should not attempt to write to or manage log files. Instead, each running process writes its event stream, un-buffered, to stdout.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; hard code any logger configuration. These values should also be set in the application configuration to allow for flexibility in updating this in production environments without having to create new releases.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use highly unique values for metric tags and log context like GUID IDs. This applies a strain on indexing of these logs and metrics and while tools in use may apply constraints on these or result in increased cost of usage. Instead use values you would likely be applying to bucket of data on like request method type, response status code, exception type, etc.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use string interpolation with logs. Instead, adopt the &lt;a href=&quot;https://messagetemplates.org/&quot;&gt;message templates&lt;/a&gt; approach of structured logging.&lt;/p&gt;
&lt;p&gt;A couple of reasons&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Highly unique Logs are a strain on log indexes for log targets&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;$&amp;quot;Deleting file: {&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FileContentId&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;//This creates unique logs for each file&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Logs can be searched based on the message template&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// IDEAL&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;LogInformation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Deleting file: {FileContentId}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;job&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FileContentId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;//This would allow searching by &amp;#39;Deleting file: {FileContentId}&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;Again very useful for observing our logs downstream as with most systems like Datadog, Prometheus, etc as searching by message template is more powerful and faster as opposed to substring searches.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Tests&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;An assumption that tests make use of xUnit is made here.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; aim for your tests to meet the following positive heuristics&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;run fast&lt;/li&gt;
&lt;li&gt;not break often or be flaky&lt;/li&gt;
&lt;li&gt;not be high-maintenance&lt;/li&gt;
&lt;li&gt;easy to read and understand&lt;/li&gt;
&lt;li&gt;have the same style and diligence as the code being tested&lt;/li&gt;
&lt;li&gt;be deterministic&lt;/li&gt;
&lt;li&gt;survive major refactorings&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO AVOID&lt;/strong&gt; the following negative heuristics of tests:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;🧪 Logic in tests&lt;/li&gt;
&lt;li&gt;🪄 Magic values&lt;/li&gt;
&lt;li&gt;😔 Not writing tests because &lt;code class=&quot;language-text&quot;&gt;they are difficult&lt;/code&gt; or something is &lt;code class=&quot;language-text&quot;&gt;untestable&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;🔫 Shotgun surgery (has to use unhealthy ways to perform tasks like reading private methods with reflection)&lt;/li&gt;
&lt;li&gt;🌝 Eager test (exposes a lot of irrelevant details about SUT that distract the test reader from what affects the behaviour being tested)&lt;/li&gt;
&lt;li&gt;😬 Happy path (only tests the paths where things go well)&lt;/li&gt;
&lt;li&gt;🦥 Slow Poke (where you grab a coffee while they run)&lt;/li&gt;
&lt;li&gt;🦣 Giant (super big test, the day it has issues it’s commented out)&lt;/li&gt;
&lt;li&gt;🤡 Mockery (mocking on steroids)&lt;/li&gt;
&lt;li&gt;🔎 Inspector (violates black box approach)&lt;/li&gt;
&lt;li&gt;🪰 Generous left over (when separate tests do a baton exchange of data and often (but not always!) depend on run order)&lt;/li&gt;
&lt;li&gt;🦸 Local hero (only passes in a specific environment)&lt;/li&gt;
&lt;li&gt;🐜 Nitpicker (much like inspector but focuses on irrelevant specifics that are most likely to change easily/often)&lt;/li&gt;
&lt;li&gt;📢 Loud mouth (clutters console with diagnostic messages)&lt;/li&gt;
&lt;li&gt;🤥 The liar (skips red-green-refactor, mocked SUT, not specific enough leading to false positives)&lt;/li&gt;
&lt;li&gt;🆓 Free ride (assertions that piggyback on an existing test when that should be split out)&lt;/li&gt;
&lt;li&gt;🔮 Mystery guest (test reader is not able to see the cause and effect between act, arrange, and assert because stuff is magically done elsewhere)&lt;/li&gt;
&lt;li&gt;🤫 Useless test (Shush) (Shush) (requires manual debugging to figure out what caused a test to fail)&lt;/li&gt;
&lt;li&gt;🪲 Flaky test (fails under specific conditions like time of day, day of the week)&lt;/li&gt;
&lt;li&gt;💹 High maintenance tests (UI-driven tests are a pathway to this hell)&lt;/li&gt;
&lt;li&gt;🐡 Lost tests (they do nothing, maybe good refactored to oblivion, they never did anything in the first place)&lt;/li&gt;
&lt;li&gt;🔏 Using uncleansed data (for example prod data as is in the test potentially exposing this)&lt;/li&gt;
&lt;li&gt;⚙️ Ignoring business needs or issues (tests or test approaches that focus only on the technology)&lt;/li&gt;
&lt;li&gt;🕔 Involving testing late&lt;/li&gt;
&lt;li&gt;🤐 Secret catcher (relies on exceptions happening in the code and being caught by the test runner)&lt;/li&gt;
&lt;li&gt;🔢 Line hitter (meant to appease the gatekeeper of the code coverage metric)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of &lt;strong&gt;traits&lt;/strong&gt; to segment tests, such as marking integration tests separately from unit tests. This brings significant advantages in managing and executing tests, especially in a continuous integration (CI) environment. By using traits, like the ones available in xUnit.NET, you can easily categorize and selectively run tests based on their characteristics. This helps with granular test execution as required, test result analysis and parallel test execution control.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Trait&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;TestCategory&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TestCategories&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Integration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AnalysisDatabaseTests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TestCategories&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Integration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Integration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In CI, the tests can be targetted with a filer, for example, the following command only runs integration tests&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;dotnet test --filter TestCategory=Integration&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; write more tests. In particular, areas that require tests at all times are&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Algorithms&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Intricate business logic&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Helpers and Utilities&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Resolved bugs&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ In addition to having more test coverage that helps with more confidence to change existing code and ensuring that previously discovered regressions do not occur again, tests are very good at identifying issues, especially around the coupling. Code that violates certain core principles that ensure a healthy and maintainable code base is very difficult to test, writing more tests allows us to see this upfront.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; name mocks vs mock object instances accordingly. Mocks from &lt;code class=&quot;language-text&quot;&gt;automock&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;new Mock&amp;lt;T&gt;()&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;Mock.Of&amp;lt;T&gt;&lt;/code&gt; should have the suffix mock but not the object instances from &lt;code class=&quot;language-text&quot;&gt;mock.Object&lt;/code&gt; i.e. userMock for the mock and user for the object.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ This distinction can go a long way in the readability of tests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the name SUT for the &lt;code class=&quot;language-text&quot;&gt;system under test&lt;/code&gt;. This small detail shines particularly when the test is heavy in the arranging stage, it needs to be clear what the SUT is.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;10&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;autoMock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Create&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SecurityProvider&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CreateToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SecurityTokenRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NotBeNullOrWhiteSpace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consistently use a builder for &lt;code class=&quot;language-text&quot;&gt;EF Core Data Contexts&lt;/code&gt; for creating a test data context. Having one place to create the data context will make it easier to maintain this over time should you need to make a change to the data context for all tests and remove boilerplate code.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;11&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InMemoryDataContextBuilder&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SupportDataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BuildSupportDataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DbContextOptionsBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SupportDataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;UseInMemoryDatabase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Freeze&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SupportDataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DbContextOptionsBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;UseInMemoryDatabase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Freeze&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NullLoggerFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DbContextOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ILoggerFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;loggerFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;configure&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ??= &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetDefaultDbContextOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;loggerFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ??= &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NullLoggerFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;loggerFactory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DbContextOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetDefaultDbContextOptions&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DbContextOptionsBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;UseInMemoryDatabase&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToString&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Freeze&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅  &lt;strong&gt;DO&lt;/strong&gt; consider a data generator like &lt;a href=&quot;https://github.com/bchavez/Bogus&quot;&gt;Bogus&lt;/a&gt; paired builders.&lt;/p&gt;
&lt;p&gt;This will allow you to easily generate realistic and randomized test data. This is particularly useful when you need a large set of diverse data for your tests. Instead of manually creating test data, you can use Faker to generate it automatically, saving you time and effort&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of test builders for objects that potentially would get created over and over in tests.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;12&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// base implementation&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;abstract&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;abstract&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;implicit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[((&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MemberExpression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Member&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TryGetValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MemberExpression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Member&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                ? &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;dynamic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                : &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Example implementation&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;UserBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;UserBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;UserBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;override&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;UserBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Test&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Test1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;User&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;John Doe&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Follow this principle for any object that gets created over and over in multiple tests, which should have a builder as one authoritative way to create it for tests.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;🎃 &lt;strong&gt;DO&lt;/strong&gt; be aware of a &lt;strong&gt;GOTCHA&lt;/strong&gt; with working with the EF core in-memory data context. This implementation chooses to enforce referential integrity for navigation properties. If you create an object that has a &lt;code class=&quot;language-text&quot;&gt;non-nullable&lt;/code&gt; navigation property but leaves this as null and then adds it into the data context in your test, any attempt to read this back out will not return anything. All &lt;code class=&quot;language-text&quot;&gt;non-nullable&lt;/code&gt; navigation properties will have to be &lt;code class=&quot;language-text&quot;&gt;non-null&lt;/code&gt; as well for this to work. Quite the annoyance for tests but currently with no workaround.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO&lt;/strong&gt; not use the xUnit’s &lt;code class=&quot;language-text&quot;&gt;MemberData&lt;/code&gt; attribute for primitive types, only use this for complex types that cannot use &lt;code class=&quot;language-text&quot;&gt;InlineData&lt;/code&gt;. &lt;code class=&quot;language-text&quot;&gt;InlineData&lt;/code&gt; makes it easy to see the test and its test data easily, you lose this with a separate method for member data.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;13&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Theory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InlineData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InlineData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InlineData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot; &amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InlineData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;){}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// IS BETTER THAN&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Theory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MemberData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TestData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;){}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Naming and structure&lt;/h3&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; name test projects in the format &lt;code class=&quot;language-text&quot;&gt;[name of project under test].tests&lt;/code&gt; ensuring that the suffix &lt;code class=&quot;language-text&quot;&gt;tests&lt;/code&gt; is always used. This makes it easy to identify test projects especially when you want to apply filters like in &lt;code class=&quot;language-text&quot;&gt;Directory.Builds.props&lt;/code&gt; or in build pipelines.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; name test files with the same name as the file being tested with the suffix Tests i.e. &lt;code class=&quot;language-text&quot;&gt;UtilsTests.cs&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; mirror the folder structure of what is being tested in tests - &lt;code class=&quot;language-text&quot;&gt;/Services/Access/UserAccess.cs&lt;/code&gt; -&gt; &lt;code class=&quot;language-text&quot;&gt;/Services.Tests/Access/UserAccessTests.cs&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor naming tests in the format &lt;code class=&quot;language-text&quot;&gt;Given_Then_Should&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;Given_When_Then_Should&lt;/code&gt;. Long test names are perfectly fine provided they give a good insight into what the test is about.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ This is particularly important as it makes it easy to navigate and find tests. Another key reason is those test runners (xUnit, Resharper), etc. parallelize tests at a project level, so if you have a test project with a ton of tests that becomes the critical path and you miss out on faster test runs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; place tests above any auxiliary methods in a test file. All helper methods should be at the bottom of the tests.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; test multiple projects by adding all the tests in one project. The test projects ideally should mirror the project structure of what is being tested.&lt;/p&gt;
&lt;h3&gt;Implementation&lt;/h3&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use Fluent Assertions for assertions over xUnit assertions. These are more readable, flexible, and powerful.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;XUnitToFluentAssertionsAnalyzer&lt;/code&gt; offers a Roslyn analysis rule enforcing this, so if you right xUnit assertion the build would fail.&lt;/p&gt;
&lt;h1&gt;XFA001: Use FluentAssertions equivalent&lt;/h1&gt;
&lt;p&gt;dotnet_diagnostic.XFA001.severity = error&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; add generic test constructs such as builders and test data that can and should be reused in multiple test projects to a common shared project i.e. &lt;code class=&quot;language-text&quot;&gt;Tests.Common&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; apply discipline within xUnit test projects by configuring the in-built Roslyn analyzers that ship with the core package as you would with any other standards. Particularly with new projects configure this to be very strict from the onset and gradually tweak this as you go along. Below is an example of a very strict configuration for xUnit.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;editorconfig&quot; data-index=&quot;14&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;[*.cs]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit1004: Test methods should not be skipped&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit1004.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit1006: Theory methods should have parameters&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit1006.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit1008: Test data attribute should only be used on a Theory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit1008.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit1013: Public method should be marked as a test&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit1013.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit1014: MemberData should use nameof operator for member name&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit1014.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit1025: InlineData should be unique within the Theory it belongs to&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit1025.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit1026: Theory methods should use all of their parameters&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit1026.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2000: Constants and literals should be the expected argument&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2000.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2003: Do not use equality check to test for null value&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2003.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2004: Do not use equality check to test for boolean conditions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2004.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2007: Do not use typeof expression to check the type&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2007.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2008: Do not use boolean check to match on regular expressions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2008.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2009: Do not use boolean check to check for substrings&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2009.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2010: Do not use boolean check to check for string equality&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2010.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2012: Do not use Enumerable.Any() to check if a value exists in a collection&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2012.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2011: Do not use empty collection check&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2011.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2013: Do not use equality check to check for collection size.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2013.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2015: Do not use typeof expression to check the exception type&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2015.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2017: Do not use Contains() to check if a value exists in a collection&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2017.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2018: Do not compare an object&amp;#39;s exact type to an abstract class or interface&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2018.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# xUnit2019: Do not use obsolete throws check to check for asynchronously thrown exception&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.xUnit2019.severity = error&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;# XFA001: Use FluentAssertions equivalent&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;dotnet_diagnostic.XFA001.severity = error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour data-driven tests where applicable over duplicated tests. This can be achieved with &lt;code class=&quot;language-text&quot;&gt;Theories&lt;/code&gt; using &lt;code class=&quot;language-text&quot;&gt;InlineData&lt;/code&gt; for compile time constants and &lt;code class=&quot;language-text&quot;&gt;MemberData&lt;/code&gt; for the rest.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;15&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Theory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InlineData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;yes&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;InlineData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;no&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Theory&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MemberData&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;nameof&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TestCases&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fileName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedExtension&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;IEnumerable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[]&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TestCases&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// input, expected&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[] {&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;test.txt&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;.txt&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;},&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make it easy to tell apart the &lt;code class=&quot;language-text&quot;&gt;Arrange&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Act&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;Assert&lt;/code&gt; sections of your test and in particular to test what the system under test (&lt;code class=&quot;language-text&quot;&gt;sut&lt;/code&gt;) is.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; write tests that assert a single concept. While a single assert per test would be ideal, it is not realistic. Fluent assertions do have constructs in place to avoid situations where you have multiple related asserts that short circuit on the first failure.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;16&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Fact&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = ...;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// CLASSIC&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// BETTER&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedResult&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = ...;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BeEquivalentTo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedResult&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// can omit properties&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BeEquivalentTo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expectedResult&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Excluding&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// ALTERNATIVE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;//Use this approach when necessary!&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AssertionScope&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ This is also possible with collections&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the most specific assertions, these give the most specific and useful failure messages as well.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;17&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BAD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// GOOD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BeTrue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BAD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;actual&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Any&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;BeTrue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Expected True, but found False.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// GOOD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;actual&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NotBeEmpty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Expected collection not to be empty.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;More examples &lt;a href=&quot;https://fluentassertions.com/tips/&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ There are Roslyn analyzers that ship with the core package to help enforce this.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; inject a &lt;code class=&quot;language-text&quot;&gt;NullLoggerFactory&lt;/code&gt; into tests unless you are interested in asserting the logs, then in that case use consider &lt;code class=&quot;language-text&quot;&gt;LoggerFactory&lt;/code&gt; double.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of xUnit fixtures for setups that can be shared by an entire test file (Class Fixtures) or multiple test files (Collection Fixtures). The example below is a class fixture that bootstraps &lt;code class=&quot;language-text&quot;&gt;AutoMapper&lt;/code&gt; for use within a single test file.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;18&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AutoMapperFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProfile&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProfile&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Profile&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AutoMapperFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mapper&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MapperConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cfg&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cfg&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AddProfile&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProfile&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CreateMapper&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IMapper&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mapper&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleTests&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IClassFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AutoMapperFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MappingProfile&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IMapper&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_mapper&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SampleTests&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AutoMapperFixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MappingProfile&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_mapper&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fixture&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mapper&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following
⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; mix business logic with code that has direct access to infrastructure for example sending an email via SMTP, reading/writing a file, calling into system constructs such &lt;code class=&quot;language-text&quot;&gt;DateTime.Now&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Task.Delay&lt;/code&gt; etc.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ A core principle with tests is that they should have full control over the `sut which becomes problematic when you violate this rule. Infrastructure concerns should be implemented as adaptors and injected into code that requires it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;19&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// PORT&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDelayService&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Delay&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TimeSpan&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;delayDuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;continueWith&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// ADAPTOR&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;internal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DelayService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDelayService&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;virtual&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Delay&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TimeSpan&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;delayDuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;continueWith&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Run&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; () =&amp;gt; { &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Delay&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;delayDuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;); })&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ContinueWith&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;continueWith&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ConfigureAwait&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// TEST STUB&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;internal&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DelayServiceStub&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;DelayService&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AutoResetEvent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DelayComplete&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;AutoResetEvent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;override&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Delay&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TimeSpan&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;delayDuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Action&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;continueWith&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;base&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Delay&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TimeSpan&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Zero&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;continueWith&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DelayComplete&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; have magic values in tests. Simple approaches like inlining variables to have a name can go a long way in test readability.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;20&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BAD - why is this particular value of significance&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Count&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Should&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Be&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; write tests with multiple responsibilities, instead a test should have a single focus. Multiple unrelated assertions are a red flag.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; mock the &lt;code class=&quot;language-text&quot;&gt;SUT&lt;/code&gt;. A key thing with the tests is to trust what is done in the act phase, which becomes hard when the &lt;code class=&quot;language-text&quot;&gt;SUT&lt;/code&gt; is being mocked as well.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; have conditional logic in tests. Rather make data-driven tests with theories or separate tests even.&lt;/p&gt;
&lt;h3&gt;Mocking&lt;/h3&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use Moq to mock necessary dependencies within a test.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider when to use &lt;code class=&quot;language-text&quot;&gt;Mocks&lt;/code&gt; vs &lt;code class=&quot;language-text&quot;&gt;TestDoubles&lt;/code&gt; very carefully. Mocks should be a natural first choice, using doubles in cases where you cannot mock such as when dealing with library concrete classes, abstract classes, etc.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;Mock.Of&amp;lt;&gt;&lt;/code&gt; when no setup or assertions are required, over &lt;code class=&quot;language-text&quot;&gt;new Mock&amp;lt;&gt;&lt;/code&gt;+ &lt;code class=&quot;language-text&quot;&gt;mock.object&lt;/code&gt;. Example:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;21&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// OK&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BETTER, more succinct&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sut&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Configuration&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; validate app configuration on startup. Consider the use of FluentValidation for this. This will help you fail fast with regards to configuration immediately on a new deployment as opposed to hours/days later when an action that requires the configuration finally fires.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ FluentValidation has great support out of the box for writing unit tests on validators, make sure to take advantage of this.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;🛑 &lt;strong&gt;DO&lt;/strong&gt; avoid reading configuration into a pre-initialized object. Creating an options class and hydrating it could lead to a situation where if the section is missing it will proceed silently, you will have an object with defaults for the properties and the app may not fail earlier or at all (by inconsistently handling cases with viable yet invalid config).&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;22&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;appConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApplicationConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configurationName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Bind&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;appConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BETTER&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;appConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configuration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetSection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;configurationName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApplicationConfiguration&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Now we would get null options if the section is missing and we can handle that case.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Language Features&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour types that carry context over the context in the naming or otherwise assumed context. i.e. Favor the use of the &lt;code class=&quot;language-text&quot;&gt;TimeSpan&lt;/code&gt; type over a numerical value with a suffix in the name such &lt;code class=&quot;language-text&quot;&gt;CacheExpiryDays&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ The &lt;code class=&quot;language-text&quot;&gt;TimeSpan&lt;/code&gt; type, in particular, is handled well in dotnet, for instance, you can use this with configuration and set your string config as &lt;code class=&quot;language-text&quot;&gt;&apos;00:00:00&apos;&lt;/code&gt; without having to worry about type conversions on reading config to a numeric type.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider using Enum Flags together with the relevant operator and &lt;code class=&quot;language-text&quot;&gt;Enum.HasFlag&lt;/code&gt; where possible over entities with multiple properties indicating Boolean states particularly when these are stored.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;23&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Flags&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;UserFlags&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;SystemAccount&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Locked&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Disabled&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour &lt;code class=&quot;language-text&quot;&gt;using&lt;/code&gt; directives instead of fully qualified type names. This helps to make the code cleaner.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;24&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Avoid this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Collections&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Generic&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// In favour of this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Collections&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Generic&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider adding imports into the namespace when you have multiple imports from the current project. This will clean up the imports as they will no longer need to be fully qualified imports.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of async overloads where available i.e. &lt;code class=&quot;language-text&quot;&gt;ToListAsync()&lt;/code&gt; over &lt;code class=&quot;language-text&quot;&gt;ToList()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; design code for async support upfront for Services/Usecases. Adding async support for a service method that has been reused in many places because there is now an await can be quite the refactor.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor &lt;code class=&quot;language-text&quot;&gt;Enumerable.Empty&amp;lt;T&gt;&lt;/code&gt; over new &lt;code class=&quot;language-text&quot;&gt;new List&amp;lt;T&gt;&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Array.Empty&amp;lt;T&gt;&lt;/code&gt; over &lt;code class=&quot;language-text&quot;&gt;new T[] {}&lt;/code&gt;. The static empty will return a compile-time constant as opposed to making a new empty allocation. This can be particularly troublesome when done in loops at scale and will put pressure on the garbage collector. This is also intent-revealing and makes it clear that the case is an empty list with no intent to add elements after&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;25&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;skip&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;skip&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Enumerable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Empty&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour returning empty collections over nulls, particularly for data that crosses boundaries. An operation-like iteration over an empty collection is safe and does not lead to exceptions as would null objects.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour the use of file-scoped namespaces over block-scoped namespaces particularly to benefit from less indentation.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;26&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// ditch this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleNamespace&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleClass&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// for this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleNamespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleClass&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make types static accordingly if there is no need for allocations, especially for things like utilities. This is also applicable to anonymous methods in C# 9 and forward and in particular makes it explicit that a lambda must not capture variables (should not be a closure).&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; add a default None (semantically an unknown or invalid) of 0 to all Enums. This makes transmitting data over HTTP safer as unset Enum props will not default to a valid value by mistake.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;27&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;enum&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleEnum&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour using declarations over blocked scoped &lt;code class=&quot;language-text&quot;&gt;usings&lt;/code&gt; thereby reducing indentation and making code more readable.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;28&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// ditch this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SqlConnection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;OpenAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CreateCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CommandText&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = ...;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ExecuteScalarAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// for this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SqlConnection&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;OpenAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;conn&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CreateCommand&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CommandText&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = ...;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cmd&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ExecuteScalarAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use negations in code unless necessary as those tend to be harder to read/comprehend&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;29&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// This is easier to read&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ? &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// This is harder to read&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = !&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;isValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ? &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; abuse null safety checks in a way that breaks the null semantics of a type in the interest of defensive coding. This can create confusion about what can be null and cascade from there as other developers extend the code.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;30&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;child&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// if any of these properties cannot be null then the defensive coding should not be applied.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; name async methods with an Async suffix, i.e. &lt;code class=&quot;language-text&quot;&gt;GetDataAsync&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Unless you are designing a library and adding async support side by side to the non-async (method overloads cannot differ only by return type) that is not warranted. In the CLR that was the exact use case for Microsoft and why they added that suffix leading to its adoption as a standard by many. However, given that most of us are either writing support on methods for one of the two but not both at the same time this rule should have been the exception really&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;async void&lt;/code&gt;. void returning async methods have a specific purpose: to make asynchronous event handlers possible. Async void methods have different error-handling semantics. When an exception is thrown out of an async Task or async &lt;code class=&quot;language-text&quot;&gt;Task&amp;lt;T&gt;&lt;/code&gt; method, that exception is captured and placed on the Task object. With async void methods, there is no Task object, so any exceptions thrown out of an async void method will be raised directly on the &lt;code class=&quot;language-text&quot;&gt;SynchronizationContext&lt;/code&gt; that was active when the async void method started.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of dictionaries and lookups in scenarios that call for them. In cases where data is loaded into a collection (list/array) and then enumerated for single/first or a group by some key like an id, that would best be a Dictionary for &lt;code class=&quot;language-text&quot;&gt;one key → one value&lt;/code&gt; or Lookup &lt;code class=&quot;language-text&quot;&gt;one key → multiple values&lt;/code&gt; and would give better performance at scale.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;31&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Before&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;entities&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Entity&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsNoTracking&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Special&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToListAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// later usage in a loop&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;targetName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;entities&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;FirstOrDefault&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;targetId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)?.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Dictionary&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;entities&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Entity&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsNoTracking&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Special&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToDictionaryAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;entities&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TryGetValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;targetId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;targetName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Lookup&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// Assuming multiple entities can have the same ID&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ILookup&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;entities&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Entity&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsNoTracking&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Special&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToLookup&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;targetNames&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;entities&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;targetId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToArray&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour the modern ways to test for nullability in C#. &lt;code class=&quot;language-text&quot;&gt;is&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;is not&lt;/code&gt; check for true nulls ignoring any operator overrides. By default the modern checks give a compiler error when the value is not nullable, the legacy gives a warning. This of course can be configured with Roslyn as desired.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;32&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// legacy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) { }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; != &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) { }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// modern&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) { }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {  }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; simplify assignment on null variables with the single assignment &lt;code class=&quot;language-text&quot;&gt;target-typed new&lt;/code&gt; operator &lt;code class=&quot;language-text&quot;&gt;?==&lt;/code&gt;. This is more succinct and the intent is easier to see on reading a single line.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;33&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// legacy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Request&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Special&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// modern&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ??= &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Request&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Special&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; split LINQ where clauses to make code more readable.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;34&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// before&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Samples&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsNoTracking&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; !&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Deleted&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;targetId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;amp;&amp;amp; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Special&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToListAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// after&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Samples&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsNoTracking&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; !&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Deleted&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;targetId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Special&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToListAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; split LINQ methods onto multiple lines for readability.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;35&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// before&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;customFields&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Samples&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsNoTracking&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; !&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Deleted&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;targetId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Special&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToListAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// after&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Samples&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsNoTracking&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; !&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Deleted&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;targetId&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Special&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToListAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour the modern &lt;code class=&quot;language-text&quot;&gt;switch expressions&lt;/code&gt; over `switch statements. This makes for more succinct code that is easier to read and takes a functional approach.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;36&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// legacy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;? &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;recommendation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;switch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;case&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TrafficLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;recommendation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Stop&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;case&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TrafficLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;recommendation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Go&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;case&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TrafficLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;amber&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;recommendation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Proceed with caution&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;recommendation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;TrafficLight malfunction: proceed with caution&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;              &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// modern&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;? &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;recommendation&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;switch&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TrafficLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;red&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Stop&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TrafficLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;green&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Go&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TrafficLight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;amber&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Procced with caution&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;TrafficLight malfunction: proceed with caution&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favour expression bodies for methods, properties, and ctors for single expressions for a more succinct syntax.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;37&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// legacy&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sampleService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleDto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Sample&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsNoTracking&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToListAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// modern&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sampleService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TranslateAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;keyword&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleDto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Sample&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsNoTracking&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToListAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; prefer pure functions. Given the same input, the same data should always be retrieved. Avoid mutations or any other side effects in functions. The effect will be functions that are easy to reason about, easy to consume with no assumptions, and certainly easier to test as well.&lt;/p&gt;
&lt;h1&gt;Web APIs&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; name controllers with a Controller suffix and use plural names for the RESTful APIs, e.g. UsersController instead of UserController.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; inject a cancellation token from the controller action and drill this down to pass to relevant calls that are cancellable. If an async call is cancelled no additional CPU/Memory needs to be used and pending processes can be cancelled.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the &lt;code class=&quot;language-text&quot;&gt;FromServices&lt;/code&gt; attribute to localize dependency injection in controllers. This is most useful when you have a bloated ctor with dependencies that are only used by all controller actions. This removes injection bloat from the ctor and makes it clear where dependencies are used.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;38&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// before&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_dependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_dependency2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SampleContoroller&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dependency2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_dependency1_&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_dependency2_&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dependency2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpGet&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;one&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleDto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;One&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FromQuery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_dependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpGet&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;two&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleDto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Two&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FromQuery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_dependency2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// after&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpGet&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;one&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleDto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;One&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FromQuery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FromServices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dependency1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpGet&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;two&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleDto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Two&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FromQuery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FromServices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDependency2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dependency2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;dependency2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;39&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;HttpGet&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;sample&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleDto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FromQuery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FromServices&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ISampleService&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) =&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;service&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// Sample service&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleDto&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;GetSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FromQuery&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleRequest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;           &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;CancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            ....&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DataContext&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Samples&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;AsNoTracking&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ToListAsync&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;cancellationToken&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️Know when you have passed a point of no cancellation to ensure atomic actions&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the type route constraint for actions. Among many, the following examples show the benefit of endpoint resolution.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;40&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApiController&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;api/[controller]&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleController&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ControllerBase&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;{id}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;{name}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Calling this with &lt;code class=&quot;language-text&quot;&gt;api/sample/10&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;api/sample/sample&lt;/code&gt; will both give the &lt;code class=&quot;language-text&quot;&gt;AmbiguousMatchException&lt;/code&gt;. This can be resolved as:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;41&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ApiController&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;api/[controller]&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleController&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ControllerBase&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;{id:int}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;{name:string}&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Sample2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠ Route constraints have features that can make them tempting to use for input validation such as ranges and regex. Don’t use constraints for input validation. If constraints are used for input validation, invalid input results in a 404 Not Found response. Invalid input should produce a 400 Bad Request with an appropriate error message. Route constraints are used to disambiguate similar routes, not to validate the inputs for a particular route. When creating params from the URL, &lt;code class=&quot;language-text&quot;&gt;required&lt;/code&gt; is a good exception to this rule as this should be useful in disambiguating routes.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Code Analysis&lt;/h1&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; suppress Roslyn analyzer rules, these are in place for a reason. Do consult other developers before suppressing rules, whether for specific code lines, files, or the entire solution to ensure that any changes that are related to standards have a team consensus.&lt;/p&gt;
&lt;h1&gt;GOTCHAS&lt;/h1&gt;
&lt;p&gt;✨ Apply caution when changing code surrounded by debugger directives. Ideally building with the debug or release config should not make a difference to the build’s succeeding. However with preprocessor directives if you change code that is only available for release, for instance, it could end up broken and you would not pick it up on your dev machine as you are building in debug. This would of course blow up later when you are making release builds. Be mindful of this scenario.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠ Historically Visual Studio has not been particularly smart with these scenarios, it could suggest for instance that you remove an unused using that is used in a preprocessor directive for a mode you are currently not running in.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✨ Apply caution with &lt;code class=&quot;language-text&quot;&gt;CopyToOutputDirectory&lt;/code&gt; option &lt;code class=&quot;language-text&quot;&gt;Always&lt;/code&gt; as this will break incremental builds and cause given projects to always build even when they have not been updated. Do make use of the option &lt;code class=&quot;language-text&quot;&gt;PreserveNewest&lt;/code&gt;. In addition, this option means less IO, particularly for large files which also speeds up builds.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ Such cause is not obvious and an investigation must be conducted to find the glitch. To investigate, in the &lt;em&gt;Visual Studio &gt; Options &gt; Projects and Solutions &gt; SDK-Style Projects&lt;/em&gt;, set the &lt;em&gt;&lt;strong&gt;Up to Date Checks&lt;/strong&gt;&lt;/em&gt; value from &lt;em&gt;None&lt;/em&gt; to &lt;em&gt;Minimal&lt;/em&gt;. Now in the Output window, you will see logs that indicate when incremental builds are not working as expected and why&lt;/p&gt;
&lt;/blockquote&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk17 { color: #808080; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk14 { color: #F44747; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[How you do something, is how you do everything]]></title><description><![CDATA[Photo by Àlex Rodriguez on Unsplash How you do something is how you do everything How often do we as individuals or collectively in groups…]]></description><link>http://www.drunkonmonads.com/how-you-do-something-is-how-you-do-everything/</link><guid isPermaLink="false">http://www.drunkonmonads.com/how-you-do-something-is-how-you-do-everything/</guid><pubDate>Wed, 24 Aug 2022 18:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@alexabad?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Àlex Rodriguez&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/wallpapers/cool/good?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;How you do something is how you do everything&lt;/h1&gt;
&lt;p&gt;How often do we as individuals or collectively in groups put off certain things as inconsequential, and rush to deliver something that is “good enough”? How often do we put off a small-time investment to polish up on anything because it is not that important? This is a typical mindset and one that may not be entirely conscious if it has been done long enough to become a habit. Some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;That email that is sent out with grammar issues that creates a negative impression of you and the team you represent.&lt;/li&gt;
&lt;li&gt;The lack of artifacts and documentation in a team for things like onboarding and offboarding of new colleagues or documentation of processes and practices.&lt;/li&gt;
&lt;li&gt;The tardiness to the meeting that is only a few minutes, and no one should notice, right?&lt;/li&gt;
&lt;li&gt;The hastiness when delivering feedback that leaves out the key details.&lt;/li&gt;
&lt;li&gt;That one thing you keep telling yourself you will get to but never do.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Often, we put off doing things properly as either being insignificant or demanding too much time that we do not have yet. A lot of times we end up having to revisit that same thing again and again due to not getting it right the first time.&lt;/p&gt;
&lt;p&gt;Over the years I have noticed that teams or individuals that don’t mind dropping the ball in one area believing it is not all that significant all tend to have the following traits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Lack of unanimity on what areas are okay to drop the ball on and as such eventually things spiral out of control as everyone makes their own decisions on what to mediocre in.&lt;/li&gt;
&lt;li&gt;Communication is not great in these teams, and it usually only takes one or two individuals to not do it well and be allowed to, for the whole team to struggle in this area.&lt;/li&gt;
&lt;li&gt;Tasks that can be done right once and replicated with ease are instead rushed and then repeated haphazardly and without consistency.&lt;/li&gt;
&lt;li&gt;Lack of consistency in delivery. A tell-tale sign is when you can look at what is delivered and easily tell which team member worked on what.&lt;/li&gt;
&lt;li&gt;An ever-growing list of things that get put off that no one ever gets to.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A key observation for me has been that the situation increasingly gets worse over time and the same attitude starts to get applied in other areas that are not too apparent but have consequences regardless. The broken windows theory explains why things we put off ultimately spiral out of control by stating that any observable signs of disorder such as broken windows form an environment that encourages even more disorder. Consequently, by ignoring the “little” things you soon forfeit control of much more to this mindset. After all, if you allow your hedge to overgrow, would you notice when your lawn requires a trim?&lt;/p&gt;
&lt;p&gt;So how do we manage this? Well, we tackle this much like Mayor Giuliani tackled the severe issues New York City was facing before 1993. Let’s glance at some statistics on what he accomplished first (&lt;em&gt;source: The American Presidency Project&lt;/em&gt;)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In 1993, there were 11,545 major crimes per week; By 2001, that number dropped to 5,072.&lt;/li&gt;
&lt;li&gt;Between 1993 and 2001, New York City experienced a 66% decline in murders.&lt;/li&gt;
&lt;li&gt;During the same period, there was a 72% decline in shootings.&lt;/li&gt;
&lt;li&gt;In addition to the decline in murders, New York saw a 45.7% decline in rapes, a 67.2% decline in robberies, a 39.6% decline in aggravated assault, a 68.2% decline in burglary, a 43% decline in larceny, and a 73.3% decline in motor vehicle theft.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;He accomplished all this by “repairing all the broken windows”; tackling vandalism, loitering, public drinking, jaywalking, transport fare evasion, and more to create an environment that discouraged crime and disorder. Once the environment looked and felt good the residents treated it with regard and pride.&lt;/p&gt;
&lt;p&gt;Similarly, this is how we can guarantee that we remain committed to delivering at the highest standard across the board. Once the quality is baked into our minds and there is no tolerance for dropping the ball you will notice consistency, a sort of synergy even within teams as more projects and challenges are taken on. These are a few heuristics to evaluate when this is going well:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Communication is healthy. We engage professionally and expressively cultivating strong relations. We return every phone call and reply to every message and email. We express ourselves with empathy and respect.&lt;/li&gt;
&lt;li&gt;Delivery is done once and well. We do not scurry through delivery only to have to rework things at the expense of the next commitment.&lt;/li&gt;
&lt;li&gt;Processes are regularly reviewed and evaluated to ensure that no broken windows are ignored. This is key to preserving this mindset at least long enough to make it a habit.&lt;/li&gt;
&lt;li&gt;Doing things well does not have a big impact on the effort or time required to deliver, especially when repeated.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;“How you do anything, is how you do everything” has become a favoured quote of mine, and really by contemplating on this often and acting I feel it has served me well. An early experience that helped me to always aspire to do all things well was participating in athletics back in my high school days. I aimed to improve my 100m sprint time and what I noticed in my attempts was that I could not “just” improve it. To achieve that I had to improve everything it took to do the dash, even if by a teeny bit. Surprisingly that meant a whole lot of things would require attention like how well my start was, my stamina, rest, and diet, and many more had to be improved. Interestingly some of the things I had initially put off as being insignificant turned out to have the greatest impact and the success in addressing those created a habit for me to pursue the other changes with the right attitude. Soon I was applying this mindset to my academics, relationships, parenting, and work with similar success.&lt;/p&gt;
&lt;p&gt;Contemplate this and see what you can apply to yourself or your team. Here are a few questions that may guide you in that process:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Are you applying discipline and structure in all you do?&lt;/li&gt;
&lt;li&gt;When you put off things are you being critical and objective about why or are you seeking a reason to justify the action?&lt;/li&gt;
&lt;li&gt;If you continue to work in the manner and pace, you do now how will things look a year from now?&lt;/li&gt;
&lt;li&gt;Are you putting off meetings and events because you are too busy?&lt;/li&gt;
&lt;li&gt;Imagine a backlog of anything you must get done as a trashcan. Do you put off taking five minutes to empty the trashcan and ultimately must deal with a greater situation once the trash starts to spill over?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you don’t do the “unimportant stuff” well, do not be surprised if you cease doing anything well at all. Once you tolerate mediocracy in one area you have simply tolerated it in all your doings, period. It is all about doing the little things well and consistently. Apply this in your work, personal life, and everything else in between to unlock great success and satisfaction. Of course, keep an eye on doing things well by avoiding cutting corners without necessarily aiming for perfectionism as that can easily burn you out.&lt;/p&gt;
&lt;p&gt;In closing recognize this, repetition makes habits!&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[AWS Best Practices]]></title><description><![CDATA[Photo by Jon Tyson on Unsplash AWS Best Practices General ✅ DO come up with a complete and documented disaster recovery process for all the…]]></description><link>http://www.drunkonmonads.com/aws-best-practices/</link><guid isPermaLink="false">http://www.drunkonmonads.com/aws-best-practices/</guid><pubDate>Thu, 30 Jun 2022 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@jontyson?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Jon Tyson&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/backgrounds/cool/best?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;AWS Best Practices&lt;/h1&gt;
&lt;h2&gt;General&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; come up with a complete and documented disaster recovery process for all the services and workloads you utilize in AWS. Regularly review and run through the process to ensure that it stays up to date and that the team has the skills to execute it. Have a clear definition of the time to recovery and point of recovery for your workloads.&lt;/p&gt;
&lt;h2&gt;IAM&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use access keys with restricted access to only what is required for a development setup and ensure that these are not linked to a user with AWS console access.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ The access keys used by developers are the ones at most risk as multiple people will have these on their machines, therefore, increasing the surface area of compromise.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; isolate resources by environment so that generated keys access only have access to the environment it is used in. For example, development keys should not be able to access production stacks.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; set up any AWS accounts with console access that do not have MFA enabled.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; login with a root account for day-to-day operations. IAM users/roles with specific permissions to the operation should be used instead. Root accounts should only be used for operations that cannot be done with any other account.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; login with the root user account without authorization. Only one team member should have the authorization to make use of the root account.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ While this is best practice the root user credentials should be shared with at least one other person should they be required in the absence of the primary.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;ECR&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that repositories are not publicly exposed.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ There are exceptions. For example, a requirement to set up base build images for reuse would add unnecessary complexity to authenticate on each build. Given the is no company IP in creating a public build image that would be understandable.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; enable scan on push at repository level to automatically scan for vulnerabilities on any images pushed to a repository.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider a life cycle policy for cost optimization.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ This may not be ideal. The benefit of being able to get the artifacts by release number even months if not years from now may outweigh any cost implications of storing images so make this decision very carefully.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ Unfortunately the current implementation of the policies do not work well with semantic versioning making it difficult to automate a cleanup. There is an &lt;a href=&quot;https://github.com/aws/containers-roadmap/issues/1213&quot;&gt;open request&lt;/a&gt; to enable regular expression to facilitate this.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use semantic versioning for all images pushed to ECR and consistent naming.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; enable cross-region replication of ECR images.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create and push only minimal images by removing all extraneous binaries or dependencies and do not use unfamiliar base images.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create and push only minimal images by using multi-stage builds.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; regularly update the packages in container images. Consider scanning tools like &lt;a href=&quot;https://snyk.io/&quot;&gt;Snyk&lt;/a&gt; to stay on top of this.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; scan and lint all Dockerfiles. Consider &lt;a href=&quot;https://hadolint.github.io/hadolint/&quot;&gt;hadolint&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that all repositories have the immutability tag enabled to force tag updates on each push and restrict overwriting prior images.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ For reproducibility images must be immutable and for security purposes, this thwarts the possibility for attackers to push malicious versions by taking advantage of a tag that is already being pulled.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;EC2&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that instances are launched off of the list of team-approved AMIs.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that instances that have a burstable instance type have the credit specification set to enable unlimited mode.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ If the average CPU utilization over 24 hours exceeds the baseline, you incur charges for surplus credits. Which is likely okay and desired for critical workloads.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that instances have termination protection enabled, which ensures that someone does not accidentally terminate an instance, an action that cannot be undone.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ There are exceptions to this rule. Instances that are created from spot requests cannot have this setting enabled and fully managed instances such as those created by EKS for a k8s cluster should not have this setting enabled.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO CONSIDER&lt;/strong&gt; spot instances for non-critical workloads such as running builds, pull requests, etc.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the bastion/jump server pattern for access to servers that do hold production workloads or client data.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make sure a bastion/jump server allows RDP/SSH access to traffic only from specific whitelisted IP addresses.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; provide descriptive names to instances and tag them accordingly to make it easy to tell what each instance is for.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of elastic IPs for any instances whose public/private IP address is required.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; monitor and respond to events of your instances such as CPU usage, disk space usage, etc.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; regularly review and test the EC2 disaster recovery process for instances and volumes.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; utilize and configure security groups wisely as the firewall to instances, providing only required access. Implement the least permissive rules for your security groups.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of VPCs to logically isolate instances from the rest of the AWS cloud.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create any key pairs using one of the two supported formats consistently, otherwise, keys can be cross-converted between PEM and PPK using tools like putty-gen.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the most specific AMI for a workload. AMIs with the least dependencies and features that come packaged/enabled are better as these would have a smaller attack surface area therefore always choose one that provides only what is required.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ An example is the BottleRocket AMI over the AWS Linux 2 AMI for use in a Linux-based k8s cluster. BottleRocket is optimized for running docker and comes with very minimal for that.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; clean up unused instances by shutting them down or terminating them so as not to incur charges. &lt;code class=&quot;language-text&quot;&gt;Terminated instances cannot be resurrected.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that the account billing settings have the option to receive AWS Free Tier usage alerts always enabled.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;These AWS Free Tier usage alerts allow AWS to notify you when you’re exceeding 85 per cent of your usage for the month. This of course can generate noise for non-expiring AWS free tier offerings.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ You must avoid browsing the internet on an instance by all means. If you must download something from the internet rather download it on your machine and copy it over. While the security group will act as a firewall for incoming traffic there is a caveat, if the incoming traffic is in response to a request it will come through, which is why one must avoid accessing the internet from any instances to avoid exposing the instance to attackers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; regularly patch, update, and secure the operating system and applications on your instance.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; separate Amazon EBS volumes for the Operating System vs data and further group data on multiple volumes if possible i.e. database backups vs database logs.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; have any instances without encrypted EBS volumes or snapshots.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; create any snapshots or AMIs that are in a public catalogue.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; create security groups that open any traffic to the internet, including for developer access such as SSH and RDP. Any required access for servers that do not hold production workloads or client data should be via the session manager when possible.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; mishandle or lose access to access keys used to create instances. These should be stored securely as they are required to access the instances.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; disable EC2 instance metadata as this is required by various AWS services including Systems Manager for automated scanning and patching of EC2 instances. This means the &lt;code class=&quot;language-text&quot;&gt;http-endpoint&lt;/code&gt; flag should always be set to &lt;code class=&quot;language-text&quot;&gt;enabled&lt;/code&gt;. To enforce security, however, set the &lt;code class=&quot;language-text&quot;&gt;http-tokens&lt;/code&gt; option to &lt;code class=&quot;language-text&quot;&gt;required&lt;/code&gt; which enforces sending a signed token header with any instance metadata retrieval request and hence requires an IAM role which is harder to exploit. Additionally the &lt;code class=&quot;language-text&quot;&gt;http-put-response-hop-limit&lt;/code&gt; is also set to &lt;code class=&quot;language-text&quot;&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; make use of Internet Explorer or Chrome on EC2 instances as they are not very secure. Firefox should be the browser used on all instances.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create a process for security hardening of an instance such as uninstalling unnecessary programs.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make sure scaled/duplicated instances are not in the same Availability Zones as this would not offer much resilience when an entire zone is down.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of the session manager over RDP or SSH access to instances. This avoids using and exposing an SSH key or having to open ports or a bastion host and makes use of AWS KMS for secure sessions.&lt;/p&gt;
&lt;h1&gt;Naming&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; employ complete names but with standard acronyms and in all lower cases snake case:&lt;/p&gt;
&lt;p&gt;| Entity | Prefix |&lt;/p&gt;
&lt;p&gt;| -------------- | ----------------------- |&lt;/p&gt;
&lt;p&gt;| Security Group | security-group-[region] |&lt;/p&gt;
&lt;p&gt;| EC2 | ec2-instance-[region] |&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Only include the region (i.e eu-west-1) for resources that can be created in multiple regions&lt;/p&gt;
&lt;/blockquote&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[TypeScript and React standards]]></title><description><![CDATA[Photo by Scott Rodgerson on Unsplash I thought it might be worthwhile to share my very opinionated take on how best to work with TypeScript…]]></description><link>http://www.drunkonmonads.com/react-ts-standards/</link><guid isPermaLink="false">http://www.drunkonmonads.com/react-ts-standards/</guid><pubDate>Fri, 17 Sep 2021 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@scottrodgerson?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Scott Rodgerson&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/ffH_GkINfyY?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I thought it might be worthwhile to share my very opinionated take on how best to work with TypeScript and React.&lt;/p&gt;
&lt;h1&gt;React Standards and Best Practice&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider lint staged with your linting setup (&lt;code class=&quot;language-text&quot;&gt;npx lint-staged --verbose&lt;/code&gt;) to lint currently staged files. This is a more manageable way to ensure that you are not introducing lint violations. This is particularly useful when linting is added later and you have some cleanups to do as this will avoid you being overwhelmed with lint information about the whole project, only the files you have touched.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ &lt;code class=&quot;language-text&quot;&gt;lint-staged&lt;/code&gt; with &lt;code class=&quot;language-text&quot;&gt;--verbose&lt;/code&gt; flag will run linting only on git staged files showing you both warning and errors.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ DO run eslint with the cache flag &lt;code class=&quot;language-text&quot;&gt;--cache&lt;/code&gt; enabled which will only lint files changed since the last run. This may have a big impact on developer setups. Continuous integration setups will benefit if you do not use clean build agents for each run which can greatly reduce pipeline run times.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; prefer the use of interfaces over type aliases. Use type when you need specific features offered by types. The key driver is that interfaces can always be extendable while types cannot. Because interfaces map more closely to how objects work these are a good default. However, if you cannot express a type with an interface and need to use union or tuple types then type aliases would be a better choice.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; check for console runtime errors and warnings as part of your manual testing before committing to a task, there could be useful things that show up there that are easily overlooked and often easier to act when you notice them when issues are introduced.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; prefer pure functions. Given the same input, the same data should always be retrieved. Avoid mutations or any other side effects in functions. The effect will be functions that are easy to reason about, easy to consume with no assumptions, and certainly easier to test as well.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;const&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;let&lt;/code&gt; over &lt;code class=&quot;language-text&quot;&gt;var&lt;/code&gt;, using let only where a mutation is expected. The scoping semantics of var leads to bugs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Utilize linting to enforce low-hanging fruit standards like this.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ In many cases you can avoid mutable variables altogether, hence let, by thinking in a more functional way when writing code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;!x&lt;/code&gt; instead of &lt;code class=&quot;language-text&quot;&gt;x==null&lt;/code&gt;. This avoids the confusion with &lt;code class=&quot;language-text&quot;&gt;x===null&lt;/code&gt;, the former is intentionally meant to catch both null and undefined but that situation is not exactly idiomatic and can accidentally get refactored or written incorrectly in the first place as the latter.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (!&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;//&amp;#39;x&amp;#39; is falsey, so it will evaluate to false when undefined, null, or zero (0)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor the use of modern Javascript features over the more classic counterparts. Examples of features to be familiar with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Template literals (string interpolation)&lt;/li&gt;
&lt;li&gt;Rest and spread operators&lt;/li&gt;
&lt;li&gt;Destructuring assignments&lt;/li&gt;
&lt;li&gt;Object literals&lt;/li&gt;
&lt;li&gt;Arrow functions&lt;/li&gt;
&lt;li&gt;Yield&lt;/li&gt;
&lt;li&gt;Ternary operator&lt;/li&gt;
&lt;li&gt;Nullish coalescing operator&lt;/li&gt;
&lt;li&gt;Promises&lt;/li&gt;
&lt;li&gt;async and await&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; familiarize yourself with the following array methods and avoid custom implementations or 3rd party libraries for these scenarios.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;find&lt;/li&gt;
&lt;li&gt;some&lt;/li&gt;
&lt;li&gt;every&lt;/li&gt;
&lt;li&gt;includes&lt;/li&gt;
&lt;li&gt;map&lt;/li&gt;
&lt;li&gt;filter&lt;/li&gt;
&lt;li&gt;reduce&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Favor functional map, filter, reduce, forEach, some etc over collection mutation&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor the use of absolute imports over relative imports.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// given src/services/translate.ts&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// an import from /src/../something.ts&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;../../services/translate&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// changes to this regardless of where imported from&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;translate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;services/translate&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Can be achieved by adding the following to tsconfig.json&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;compilerOptions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;baseUrl&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;src&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we want to tell local imports apart from the rest we can use aliasing&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;compilerOptions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;baseUrl&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;./&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;paths&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;~component/*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;src/components/_&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;     }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// import {Login} from ‘~component/Login;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; avoid direct mutations on arrays like calling sort. Instead, make copies with the spread operator or use slicing before calling these mutations.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; Favor arrow functions for consistent lexical scoping (no mix of lexical and dynamic scoping).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Apply caution with arrow functions on render with React, each render will see a new function and this can lead to unnecessary child renders.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;See &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions&quot;&gt;here&lt;/a&gt; for more detailed comparison between arrow functions and traditional functions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor Sets for array operations like querying, uniqueness, etc.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor await of async methods over the traditional &lt;code class=&quot;language-text&quot;&gt;then&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;catch&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// looks closer to how we are doing it in C# as well&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// less nesting -&amp;gt; easier to read&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;await&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;} &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;catch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the object spread syntax over &lt;code class=&quot;language-text&quot;&gt;Object.assign&lt;/code&gt; to shallow-copy objects.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ This can be enforced with eslint prefer-object-spread rule.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; familiarize yourself with the collection entries method and its use with destructuring.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = [&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;element&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;of&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;entries&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use double quotes for strings.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use arrow functions for class methods or object literal (this will be scoped to the caller).&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use objects as maps. Make use of the JavaScript Map object when a dictionary-like type is required.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ See &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map&quot;&gt;here&lt;/a&gt; for a comparison of maps to objects.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; abuse optional chaining (Elvis Operator). Use it to show intent (that the object is nullable) and not as a safety net for cases where something would not be null.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// should be intentional&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// falsy used gives impression the whole chain from the user can be nullable&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// the typing of what is being operated on should reflect this as well&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;streetName&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;address&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;street&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;?.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; import all from a given module.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BAD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;*&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; make use of &lt;code class=&quot;language-text&quot;&gt;as&lt;/code&gt; unless absolutely required. Type assertions with &lt;code class=&quot;language-text&quot;&gt;as&lt;/code&gt; in TypeScript remove static type checking which can lead to issues.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BAD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// adding a new property on User for instance would not cause an error here&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;John Doe&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  } &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// GOOD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getUser&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;John Doe&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;Partial&amp;lt;T&gt;&lt;/code&gt; unless absolutely required. This would be similar to abusing the &lt;code class=&quot;language-text&quot;&gt;as&lt;/code&gt; keyword to map types.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ &lt;code class=&quot;language-text&quot;&gt;as&lt;/code&gt; should hardly be used unless ‘type inference’ is indeed intended for instance if you receive something from a 3rd party lib such as a value on an event and you know the type and want TS to infer that then such would arguably be a valid case for &lt;code class=&quot;language-text&quot;&gt;as&lt;/code&gt; but can still actually be avoided.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; favor the use of indexes when working with arrays if avoidable. Using an example with Axios responses, while type inference can help pinpoint when the wrong index is used, there are a lot of edge cases where this would not help out.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;useHook&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(() &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;profile&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}, []);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BETTER&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;useHook&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(() &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;promise&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [{ &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;profile&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; }, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;response&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  });&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}, []);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;Feature best practices&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider localizing all user-visible strings. If you go with localization then this should be done consistently.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider adding dirty checks to UIs that require explicit saving and provide user prompts on navigating away with changes.&lt;/p&gt;
&lt;h1&gt;Components&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create small composable components, much like lego pieces that plug together, over large monolithic components. This allows for easier to reason about components that are easy to reuse and test. This can also make responsibility boundaries very clear and in particular help isolate the state. This can also lead to more readable JSX.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;10&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// what does this do?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={styles.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;userPanel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={styles.detailsRow&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &amp;lt;span &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={styles.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;detailsColumnLeft&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &amp;lt;/span&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &amp;lt;div &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={styles.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;detailsRow&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &amp;lt;span &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={styles.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;detailsColumnLeft&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &amp;lt;span &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={styles.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;detailsColumnRight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &amp;lt;span &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;className&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={styles.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;detailsColumnRight&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// contents above were removed for brevity, but imagine the mess!&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// same component with composition&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;ActivityPanel&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &amp;lt;DetailsRow&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &amp;lt;Name /&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &amp;lt;Completion /&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &amp;lt;/DetailsRow&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &amp;lt;DetailsRow&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &amp;lt;DueDate /&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &amp;lt;CriticalPath /&amp;gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Buffer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; /&amp;gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;DetailsRow&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;ActivityPanel&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create &lt;code class=&quot;language-text&quot;&gt;safe&lt;/code&gt; defaults to state. This can make for cleaner code as opposed to say handling undefined in multiple areas. One less obvious problem when working with side effects such as network calls is that you may have your calls returning fast a majority of the time but could have edge cases were the component renders faster than the side effect and it may have unhandled cases of undefined.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;11&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// FROM&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[]&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// TO&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[]&amp;gt;([]);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; identify generic parts of a component upfront that can be reused and code these generically enough to be shared.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; constrain what a user can enter in the UI to what the rest of the system can accept. For example, do not allow input that is larger than the database constraint, file uploads are larger than allowed in the backend. Validating such cases and showing specific and clean messages is a good UX practice.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of TypeScript generics to expose typed props accordingly when you wrap around a component or accept a render component.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;12&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleComponentProps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;sampleProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ComponentType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; | &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ElementType&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;SampleComponent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;extends&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {}&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleComponentProps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// based on usage, will infer the type of T and expose component props&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;SampleComponent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;smampleProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;} /&amp;gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ The same principle should be applied to components that accept multiple data types. The inference of the type will add typing in places such as event handlers.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that the component file name is the same as the default export component.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of CSS modules. Keep this consistent and in particular, do not make use of inline styles.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor functional components. They have a simpler syntax, no confusing lifecycle methods, constructors, or boilerplate and due to being succinct are more readable.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor multiple useEffect hook sections to make code more readable, over a single useEffect hook with multiple responsibilities.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ A good heuristic for this refactoring is when you have dependencies that do not apply to everything in the useEffect, for instance, you could have a dependency on an id changing but in addition to fetching an entity with that id you fetch data that would not have changed or be dependant on the id in the same hook. This is also applicable with custom hooks that wrap around useEffect,&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider virtualizing long lists. Unvirtualized long lists can make for a very horrible user experience with performance in many cases.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; destructure props as consts at the top of the component to guard against accidental mutations.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;13&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;SampleComponent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FunctionComponent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SampleComponentProps&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;props&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ An alternative is to create read-only props. This can prove challenging when considering nested properties and one would need to be careful about collection types used as well.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ️ In many scenarios knowing that something came from a prop vs say the state should not be a detail that should be exposed in the usage as many will justify &lt;code class=&quot;language-text&quot;&gt;props.x&lt;/code&gt; communicates this.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; mark state type properties as read-only accordingly to avoid direct mutations.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;14&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ComponentState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;userIds&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FunctionComponent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;{}&amp;gt; = () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ComponentState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// these mutations are valid&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;userIds&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = [];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;userIds&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;15&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ComponentState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;userIds&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ReadonlyArray&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;number&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FunctionComponent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;{}&amp;gt; = () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ComponentState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// these mutations are not valid&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;userIds&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = [];&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;userIds&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = { &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; };&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;owner&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use dynamic properties to make mutation logic simpler.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;16&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;FunctionComponent&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;{}&amp;gt; = () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;ComponentState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;setState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;prevState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    ...&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;prevState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;[field]:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; ensure that element keys are always stable, predictable, and unique. Unstable keys (like those produced by Math.random() or use of array indexes) will cause many component instances and DOM nodes to be unnecessarily recreated, which can cause performance degradation and lost state in child components. See &lt;a href=&quot;https://jsbin.com/wohima/edit?output&quot;&gt;example&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; apply care when writing conditional renders on variables, use of falsie numbers will be rendered i.e. &lt;code class=&quot;language-text&quot;&gt;value &amp;amp;&amp;amp; &amp;lt;Component&gt;&lt;/code&gt; given 0 for value will render 0. This however works well with bools, null and undefined.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;17&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BAD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;amp;&amp;amp; &amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// ALTERNATIVE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &amp;amp;&amp;amp; &amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// ALTERNATIVE&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk10&quot;&gt;Boolean&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &amp;amp;&amp;amp; &amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Users&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;={&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;names&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; expose render component props from the wrapper when implementing the render props pattern. Best not to pick and expose as custom props upfront, usually exposing all makes for a flexible and un-opinionated render props wrapper.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; be mindful of the number of components that have state. If a value is not required for render it can be tracked without using state. Given a parent -&gt; child hierarchy it may be possible to only track state at the parent.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use correct import syntax (import ‘x’) if importing only for side effects.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;18&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;@testing-library/jest-dom/extend-expect&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; collocate things as close as possible to where they are being used.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ Keep components, functions, styles, state, etc. as close as possible to the component where it’s being used. This will not only make your codebase more readable and easier to understand but it will also improve your application performance since it will reduce redundant re-renders on state updates.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider use of [&lt;code class=&quot;language-text&quot;&gt;react-use&lt;/code&gt;](&lt;a href=&quot;https://github.com/streamich/react-use&quot;&gt;streamich/react-use: React Hooks — 👍 (github.com)&lt;/a&gt;) over creating your own custom hooks where applicable.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; move any logic that is not React specific and does not need to be reinitialized on rerender out of function component. Keep in mind that the function component body is recalled on each render, calling that logic over and over unnecessarily.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; make all fields optional or add coalescing operators on something that is not nullable as a way to go around a state that can initially be null. Instead, make this explicit.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ By making this explicit anyone who updates this code later will know to handle null in the render.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; add to state or props data than can be derived/calculated from elsewhere.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; break HTML semantics with unnecessary elements like divs that do not carry the semantic meaning of divs for other reasons like a container in which case &lt;code class=&quot;language-text&quot;&gt;Fragment&lt;/code&gt; would have been better. Abuse of HTML tags can also break a11y and can result in an unnecessarily messy DOM.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; handle navigation with click event handling unless this is absolutely desired. The first prize is to make use of HTML semantics that the browsers have support for like hyperlinks/anchor tags. This will preserve expected browser behavior like center mouse click or right click open new tab giving the user more control, mouse icon change other current or future features.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use React fully qualified name for types, i.e. &lt;code class=&quot;language-text&quot;&gt;React.Fragment&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;React.FunctionComponent&lt;/code&gt;. This is not necessary and in particular, is not used consistently, i.e. you may not find &lt;code class=&quot;language-text&quot;&gt;React.useState&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;React.useEffect&lt;/code&gt; in the same code base that uses the latter.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;19&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setUser&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;({});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;//instead&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setUser&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;({});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; work around about state that can null in some cases, be explicit about. It will be easier for anyone using that state to know to handle possible nulls.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;20&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BAD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setUser&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;({});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// GOOD&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; [&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;setUser&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;useState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; | &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;({});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO AVOID&lt;/strong&gt; customizing 3rd party components via CSS. Instead, the customization should be done via props where applicable. Such customizations are not upgrade-friendly.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO AVOID&lt;/strong&gt; uncontrolled components, that is those that access the DOM directly i.e. refs unless absolutely necessary.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO AVOID&lt;/strong&gt; the urge to replace JSX with call-to-custom functions that return JSX, this should be done sparingly and with care. If this is desired then the custom function should be a component.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠ Note that splitting component renders with functions can be good but largely an anti-pattern that can hide the fact that a component has gotten too large or has multiple concerns. This approach should be highly avoided in favor of a declarative code. Certain React-specific heuristics are not applied when you use render functions, i.e. if you have a map and call a function React cannot and will not warn you about the need for a key and you can get away with passing unstable values like indexes to use as a key and again React cannot and will not warn you. Another really nasty thing that happens with such functions is that if you are using react dev tools, they will not show up.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; have constants scattered all over a component file. Neatly place all constants at the top of the component.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; create an order to how things flow in a component and stick to it consistently. For example, you could have the order state, hooks, event handlers, functions, and render body. Applying the same order in all your components makes it quick and easy to navigate around.&lt;/p&gt;
&lt;h1&gt;Hooks&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; follow the rules of hooks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Only Call Hooks at the Top Level
&lt;blockquote&gt;
&lt;p&gt;🛑 Don’t call Hooks inside loops, conditions, or nested functions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;Only Call Hooks from React Functions
&lt;blockquote&gt;
&lt;p&gt;🛑 Don’t call Hooks from regular JavaScript functions. Instead, you can call Hooks from React function components or from custom Hooks&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ These rules can and should be enforced with linting.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; name hooks with use prefix i.e. `useRestoreHook.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; consider creating custom hooks to encapsulate custom logic that is/can be duplicated in multiple places where applicable i.e. &lt;code class=&quot;language-text&quot;&gt;useYourImagination&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; have hooks scattered all over a component file. Neatly place these at the top of the component.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;ℹ When reading through a component you will get the most out of immediately knowing its side effects and what it renders. Seeing hooks at the top and scrolling all the way down to see the render return makes this very easy. When hooks are scattered in between other methods like event handler that becomes harder.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use complex objects as dependencies on the hooks&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;You can read more on it &lt;a href=&quot;https://www.benmvp.com/blog/object-array-dependencies-react-useEffect-hook/&quot;&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1&gt;Jest and React Testing Library&lt;/h1&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; group related tests under a &lt;code class=&quot;language-text&quot;&gt;describe&lt;/code&gt; if you have multiple tests in one file.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; locate the tests very close to the file being tested. For example, you could have the &lt;code class=&quot;language-text&quot;&gt;_tests_&lt;/code&gt; folder in each subfolder with something to test.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; name test files with suffix tests i.e. &lt;code class=&quot;language-text&quot;&gt;userService.test.ts&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;breadCrumbs.test.tsx&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor data-driven tests with &lt;code class=&quot;language-text&quot;&gt;test.each&lt;/code&gt; over duplicated tests.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;21&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1970&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1969&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  [&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1950&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;11&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;],&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;])(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;isDateBefore_1970 returns relevant boolean&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, (&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;boolean&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;isDateBefore_1970&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;date&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; favor naming tests in the format &lt;code class=&quot;language-text&quot;&gt;given then should&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;given when then should&lt;/code&gt;. Long test names are perfectly fine and in particular, the ability to use any characters including spaces in jest test names makes this very flexible.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make it easy to tell apart the &lt;code class=&quot;language-text&quot;&gt;Arrange&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;Act&lt;/code&gt;, and &lt;code class=&quot;language-text&quot;&gt;Assert&lt;/code&gt; sections of your test and in particular to clearly tell what the system under test (&lt;code class=&quot;language-text&quot;&gt;sut&lt;/code&gt;) is.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO NOT&lt;/strong&gt; have &lt;code class=&quot;language-text&quot;&gt;magic values&lt;/code&gt; in tests. Simple things like inlining variables to have a name can go a long way in test readability.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;22&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// BAD - why is this value of significance?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;toBe&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; use the most specific assertions, these give the most specific and useful failure messages as well. If there is an assertion call for it, avoid the alternative of a more generic assertion with added logic in it.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; suppress linting rules, these are in place for a reason. Do consult other developers before suppressing rules, whether for specific code lines, files, or entire workspace&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; write tests with multiple responsibilities, instead a test should have a single focus. Multiple unrelated assertions are a red flag.&lt;/p&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO NOT&lt;/strong&gt; use &lt;code class=&quot;language-text&quot;&gt;ReactTestUtils&lt;/code&gt;. Use &lt;code class=&quot;language-text&quot;&gt;React Testing Library&lt;/code&gt; which is designed to enable and encourage writing tests that use your components as the end users would. &lt;code class=&quot;language-text&quot;&gt;ReactTestUtils&lt;/code&gt; has features like mocking elements, which do not simulate how a user would use the components and encourages very bad and brittle testing patterns.&lt;/p&gt;
&lt;h1&gt;GOTCHAS&lt;/h1&gt;
&lt;h2&gt;Jest&lt;/h2&gt;
&lt;p&gt;✨ When setting up a mock with &lt;code class=&quot;language-text&quot;&gt;jest.mock&lt;/code&gt;, ideally you may want to set up one of the properties based on a variable so that you can use the same value in your assertions. Jest will however fail the test complaining that mocks cannot access outside variables. This is in place to avoid dirty mocks, however, you can bypass this by simply naming the variables with the &lt;code class=&quot;language-text&quot;&gt;mock&lt;/code&gt; suffix i.e. &lt;code class=&quot;language-text&quot;&gt;mockUser&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;23&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mockUnknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;#9E9E9E&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;jest&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;mock&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;../../redux/store&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, () &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;getState&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; (): &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RecursivePartial&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RootState&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;app:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;statusColors:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;unknown:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mockUnknown&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    },&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  }),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Form validation&lt;/h2&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; make use of yup schemas for validation and mutations related to forms.&lt;/p&gt;
&lt;p&gt;✅ &lt;strong&gt;DO&lt;/strong&gt; move the yup schema outside a component unless it requires access to something in a component, like a state (which can be avoided with a different design). This avoids a new schema being created on each render. Given the inner workings of yup on each mutation the schema is cloned, so an object schema composed of multiple property schemas is cloned for each, not ideal.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;24&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// from this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formSchema&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;customMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// to this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formSchema&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;trim&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(() &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;customMessage&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⛔ &lt;strong&gt;DO&lt;/strong&gt; not use the &lt;code class=&quot;language-text&quot;&gt;shape&lt;/code&gt; unless it is desired, ideally for merging multiple schemas together. This affects the Typescript type coercion and will fail to pick up mismatches in the schema to the target type.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;typescript&quot; data-index=&quot;25&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// from this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formSchema&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;().&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;shape&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;// to this&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;const&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;formSchema&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;User&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;({&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name:&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;});&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Debugging all jest test states]]></title><description><![CDATA[Photo by Nina Mercado on Unsplash Debugging Jest tests in Visual Studio Code can greatly enhance your JavaScript testing experience. While I…]]></description><link>http://www.drunkonmonads.com/debug-passing-jest/</link><guid isPermaLink="false">http://www.drunkonmonads.com/debug-passing-jest/</guid><pubDate>Thu, 01 Jul 2021 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@nina_mercado?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Nina Mercado&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/Y_t0n-T4H5M?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Debugging Jest tests in Visual Studio Code can greatly enhance your JavaScript testing experience. While I am an avid user of the vscode-jest extension, which is incredibly lightweight and encompasses all the primary features needed for efficient testing, there’s one aspect I felt was missing: the ability to debug all tests, regardless of their state.&lt;/p&gt;
&lt;p&gt;Fortunately, customizing VS Code to enable debugging for all Jest tests, including those that pass, fail, or are in an unknown state, is quite straightforward. You simply need to modify the settings.json file in the .vscode directory of your project. By adding or updating this configuration file with the following snippet, you unlock the ability to debug every test&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;jest.debugCodeLens.showWhenTestStateIn&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;fail&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;pass&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;unknown&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;With this simple addition, you can now trigger the debugger for tests in any state. This flexibility is particularly useful for thoroughly examining test executions, ensuring that your JavaScript code behaves as expected under various scenarios. It’s a small tweak, but it significantly improves the debugging capabilities within VS Code, making the process of testing with Jest more efficient and comprehensive. Sweet!&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 283px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/71bc157d5b661b33fff48b0e6e1c29a7/9a54c/debug-jest.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 45.93639575971732%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAAAsTAAALEwEAmpwYAAABGklEQVR42pWQ3W6CMBiGuYgdyE8Up0t/6IAWaKGVCshQhpplWZbs/m9kFbMs7OfA5MmXfu+b5+CrFQaMYhpjxgK2IqlLMo9kbpBeIJfpBWb9SqZYPeP5pslyzWOeofgOJA5kLk4utZk4tXHiXFfyS+4S2ZaHvjl3XEkpQV3hSi+5NMIiKz1aPIRqxTZunDso+SkvIgV4h9QRpltQ1snpmQ8t0pUXqZVsfVET/gTydp5qPxLzUDhTWZg715sXoN/WxQnKQQj1WO7viyFoPqB+XYr9Wp1h9Z7ujlh3NmLfshMWpO4XTM4gdTCzETX1DI0PSE04JmMITTjB8qlk7Smseix3gWr/48/WWlIZ6r0h2h5uxTK/al9B7FY+AawKZhVIcpFXAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;debug jest&quot;
        title=&quot;&quot;
        src=&quot;/static/71bc157d5b661b33fff48b0e6e1c29a7/9a54c/debug-jest.png&quot;
        srcset=&quot;/static/71bc157d5b661b33fff48b0e6e1c29a7/9a54c/debug-jest.png 283w&quot;
        sizes=&quot;(max-width: 283px) 100vw, 283px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Killing node processes]]></title><description><![CDATA[Photo by Gunnar Ridderström on Unsplash Visual Studio has this annoying tendency to leave zombie node processes after you have run a node…]]></description><link>http://www.drunkonmonads.com/kill-node-process/</link><guid isPermaLink="false">http://www.drunkonmonads.com/kill-node-process/</guid><pubDate>Wed, 30 Jun 2021 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@gunnarridder?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Gunnar Ridderström&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/M95qcCum7t8?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Visual Studio has this annoying tendency to leave zombie node processes after you have run a node app from it. This can be quite expensive and leave your machine very laggy as they accumulate from multiple runs. You may also run into this situation for different reason.&lt;/p&gt;
&lt;p&gt;There are two ways to kill these zombie processes&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Kill all node processes running&lt;/li&gt;
&lt;li&gt;Target specific node processes&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To kill all node processes run the command&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;cmd&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;taskkill&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; /f /im node.exe&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This has proven to be a bit problematic for me as I sometime have node processes that I want to keep alive such as those from running VS Code and extensions or other apps. I therefore prefer to target specific node apps based on the command that is used to spawn them. For instance if using &lt;code class=&quot;language-text&quot;&gt;react-app-rewired start&lt;/code&gt; to run the app I would target that by running the following script.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;powershell&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;Get-WmiObject&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Win32_Process | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Where-Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.CommandLine&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -like &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;*react-app-rewired*start*&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -and &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; -eq &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;node.exe&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; } | &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ForEach-Object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;$_&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;.terminate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[VS Code workspace recommended extensions]]></title><description><![CDATA[Photo by Barn Images on Unsplash Visual Studio Code has support for specifying extension recommendations as part of you workspace…]]></description><link>http://www.drunkonmonads.com/workspace-recommended-extensions/</link><guid isPermaLink="false">http://www.drunkonmonads.com/workspace-recommended-extensions/</guid><pubDate>Wed, 30 Jun 2021 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@barnimages?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Barn Images&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/t5YUoHW6zRo?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Visual Studio Code has support for specifying extension recommendations as part of you workspace. Developers can then see these in the extensions tab and decide what to install.&lt;/p&gt;
&lt;h2&gt;Here is how to set it up&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/extensions-recommendation.gif&quot; alt=&quot;gif&quot;&gt;&lt;/p&gt;
&lt;p&gt;This creates a file named &lt;code class=&quot;language-text&quot;&gt;extensions.json&lt;/code&gt; under &lt;code class=&quot;language-text&quot;&gt;.vscode&lt;/code&gt; in your workspace root which looks something like this.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;recommendations&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;editorconfig.editorconfig&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Generalize .net test dependencies]]></title><description><![CDATA[Photo by Shubham Dhage on Unsplash Generalize .net test dependencies with Directory.Build.props In the .NET ecosystem, Directory.Build.props…]]></description><link>http://www.drunkonmonads.com/generalize-common-test-deps/</link><guid isPermaLink="false">http://www.drunkonmonads.com/generalize-common-test-deps/</guid><pubDate>Tue, 29 Jun 2021 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@theshubhamdhage?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Shubham Dhage&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/nMcqssE0eA0?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Generalize .net test dependencies with Directory.Build.props&lt;/h1&gt;
&lt;p&gt;In the .NET ecosystem, Directory.Build.props is a powerful feature that allows developers to apply common settings across multiple project files. It acts as a central place to define properties and item groups that are automatically imported into every project in the directory tree. This means you can specify a single version of a NuGet package or a set of common properties in one file, and these settings will propagate to all relevant projects. This approach not only streamlines the configuration process but also ensures consistency and reduces the likelihood of errors in large solutions.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;Directory.Build.props&lt;/code&gt; file offers a lot of interesting features for targeted projects, solution folders, or the entire solution. Let’s focus on how we can leverage this to generalize test dependencies and any required configuration in one place.&lt;/p&gt;
&lt;p&gt;Test project dependencies tend to be mostly the same across multiple projects and annoyingly can be quite easy to point to different versions and require consolidating. I use the &lt;code class=&quot;language-text&quot;&gt;Directory.Build.props&lt;/code&gt; at the tests folder to target all test projects, in my case by the suffix &lt;code class=&quot;language-text&quot;&gt;.Tests&lt;/code&gt; in the name, and apply the generic dependencies in one place.&lt;/p&gt;
&lt;p&gt;Utilizing Directory.Build.props offers several key benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Reduced Redundancy: By centralizing common configurations, it eliminates the need to duplicate settings across multiple project files.&lt;/li&gt;
&lt;li&gt;Ease of Updates: Updating a single &lt;code class=&quot;language-text&quot;&gt;Directory.Build.props&lt;/code&gt; file propagates changes to all projects, simplifying maintenance and version upgrades.&lt;/li&gt;
&lt;li&gt;Consistency Across Projects: Ensures uniformity in settings and dependencies, making the codebase more cohesive and manageable.”&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Example&lt;/h2&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Condition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;$(MSBuildProjectName.EndsWith(&amp;#39;.Tests&amp;#39;))&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IsPackable&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IsPackable&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Condition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;$(MSBuildProjectName.EndsWith(&amp;#39;.Tests&amp;#39;))&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Autofac.Extras.Moq&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;6.1.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;FluentAssertions&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;6.7.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;FluentAssertions.Analyzers&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;0.17.2&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;XUnitToFluentAssertionsAnalyzer&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;1.0.2&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Microsoft.NET.Test.Sdk&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;17.2.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;xunit&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;2.4.1&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;xunit.runner.console&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;2.4.1&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;runtime; build; native; contentfiles; analyzers&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;xunit.runner.visualstudio&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;2.4.5&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;runtime; build; native; contentfiles; analyzers&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;AutoFixture&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;4.17.0&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;coverlet.collector&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;3.1.2&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Condition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;$(MSBuildProjectName.EndsWith(&amp;#39;.Tests&amp;#39;))&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ProjectReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;..\Sample.Tests.Common\Sample.Tests.Common.csproj&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this example, we have all test projects marked as not being packable, setup of required package references and all tests have a project reference to a common test project that could contain shared things like fixtures, builder, etc. We no longer need to have these in each project and can control what goes in all the tests in one place.&lt;/p&gt;
&lt;p&gt;While this was specifically about tests, there are many other use cases. For example, we could set things like copyright and assembly info in one place by targeting all projects, indicating the C# language version at the solution level, etc. Cases like these are often the same for all projects but over time people forget to update some projects or it just becomes tedious to keep up.&lt;/p&gt;
&lt;h2&gt;Pitfalls&lt;/h2&gt;
&lt;p&gt;One common pitfall is inadvertently affecting projects with unwanted configurations. To avoid this, use conditional properties in your &lt;code class=&quot;language-text&quot;&gt;Directory.Build.props&lt;/code&gt; file to selectively apply settings. Another issue is the misplacement of the file; ensure it’s correctly located at the solution root or appropriate directory level. Also, be mindful of the order of properties and their overriding behavior, as this can lead to unexpected configurations.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In conclusion, &lt;code class=&quot;language-text&quot;&gt;Directory.Build.props&lt;/code&gt; is a highly effective tool in the .NET developer’s arsenal for managing project dependencies and configurations. By centralizing common settings, it not only simplifies project management but also enhances the maintainability and consistency of your codebase. As demonstrated, its benefits extend beyond test projects, offering a streamlined approach to handle various aspects of .NET development. Adopting &lt;code class=&quot;language-text&quot;&gt;Directory.Build.props&lt;/code&gt; can significantly improve the efficiency and reliability of managing large and complex .NET solutions.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk17 { color: #808080; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Make linting great again]]></title><description><![CDATA[Photo by Bruno Martins on Unsplash I am a firm believer in the role of linting in keeping code bases from decaying and enforcing standards…]]></description><link>http://www.drunkonmonads.com/make-linting-great-again/</link><guid isPermaLink="false">http://www.drunkonmonads.com/make-linting-great-again/</guid><pubDate>Tue, 29 Jun 2021 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@brunus?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Bruno Martins&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/i6Ynmfi6UBg?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I am a firm believer in the role of linting in keeping code bases from decaying and enforcing standards and consistency. Particularly, I feel linting tools really shine as code bases age. For JavaScript based projects, I find eslint to be pretty powerful but acknowledge that one thing that can keep developers from using it often is that it can be slow in running if not setup properly, especially with regards with caching and is hooked up to commits with something like husky, and if linting violations have been ignored for a while one can drown in a lot errors and warnings.&lt;/p&gt;
&lt;p&gt;My common eslint usecase is running it against files I have just added/updated and quite rarely do I need to run it on the whole solution until I am ready to open a pull request. If I do however I always make sure caching is on by using the &lt;code class=&quot;language-text&quot;&gt;--cache&lt;/code&gt; flag that only runs linting on file changed since last run.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Setup the &lt;code class=&quot;language-text&quot;&gt;--cache&lt;/code&gt; flags as part of a lint command in your package.json for ease of use&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However how do I get to run eslint only on files I just updated? The answer is simple, I use git and one easy way to narrow down these files is to have them staged.
Enter lint-staged!&lt;/p&gt;
&lt;h2&gt;lint-staged&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://www.npmjs.com/package/lint-staged&quot;&gt;Lint staged&lt;/a&gt; is a tool that runs linters against git files that are staged to stop the 💩 from slipping into your code. Notice I said linters, not eslint, so this can be used with various linting tools. Install it with &lt;code class=&quot;language-text&quot;&gt;npm i lint-staged --save-dev&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To set it up for the first time run &lt;code class=&quot;language-text&quot;&gt;npx mrm lint-staged&lt;/code&gt;. I prefer to use the .linstagedrc file for configuration and if you are using eslint you can set it up as&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;json&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;&amp;quot;*&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;eslint --cache&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I typically run my linting and manually go over any warning/errors. If you want to auto-fix what can be auto-fixed you can use the &lt;code class=&quot;language-text&quot;&gt;--fix&lt;/code&gt; flag.&lt;/p&gt;
&lt;p&gt;Once setup you can give it a go with &lt;code class=&quot;language-text&quot;&gt;npx lint-staged&lt;/code&gt;. Don’t forget off course that you need staged files for this to work. You can go a step further and set it up to auto-run with hooks by using tools such as husky.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;By default lint-staged will only show error in the run summary, to see warnings as well, which is super useful run with the &lt;code class=&quot;language-text&quot;&gt;--verbose&lt;/code&gt; flag.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Now that you can’t complain about being overwhelmed by lint violations others introduced or slow runs, what is your excuse not to take advantage or linting with eslint 😀?&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Control Home Assistant with an Apple Watch]]></title><description><![CDATA[Photo by Luke Chesser on Unsplash It’s pretty nifty and also surprisingly useful to be able to control your smart home from your wrist. What…]]></description><link>http://www.drunkonmonads.com/apple-watch-ha-actions/</link><guid isPermaLink="false">http://www.drunkonmonads.com/apple-watch-ha-actions/</guid><pubDate>Thu, 04 Mar 2021 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@lukechesser?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Luke Chesser&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/wallpapers/iphone/apple-watch?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It’s pretty nifty and also surprisingly useful to be able to control your smart home from your wrist. What you control depends on your use cases but I get to show you how to control it and maybe inspire you with how I use it. We will work based on the following use cases&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get Dustbin Bieber busy&lt;/li&gt;
&lt;li&gt;Set lounge lights to a relaxed mode&lt;/li&gt;
&lt;li&gt;Set lounge lights to max brightness&lt;/li&gt;
&lt;li&gt;Turn off all the lights&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Dustbin Bieber is our trusty &lt;a href=&quot;https://www.xiaomiproducts.nl/nl/xiaomi-roborock-s6-pure.html&quot;&gt;Roborock S6 Pure&lt;/a&gt; robot vacuum.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;First, you will need to set up actions from the Home Assistant &lt;a href=&quot;https://apps.apple.com/us/app/home-assistant/id1099568401&quot;&gt;iOS app&lt;/a&gt;. Open the app, navigate to settings -&gt; Actions, and there you will be able to add actions. You will need to specify a name for your action, which will be used as a tag, and a text description, which will be displayed on the watch, and optionally you can specify an icon and a color for both the text and icon.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/1.png&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/2.png&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/3.png&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;You should then see something like the following when opening the Home Assistant app on your Apple Watch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/4.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Executing Actions&lt;/h3&gt;
&lt;p&gt;So now we have actions showing up on our Apple Watch, but they do not do anything, well not much at least. Clicking on these actions will currently trigger an event in Home Assistant but because that event has no listener and action attached to it that is all it does. I prefer to use &lt;a href=&quot;https://nodered.org/&quot;&gt;Node Red&lt;/a&gt; to execute custom actions in Home Assistant and that is how I have set up my actions.&lt;/p&gt;
&lt;p&gt;I have set up a flow as shown in the screenshots below to execute the following.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Capture all ios events&lt;/li&gt;
&lt;li&gt;Branch on the event name&lt;/li&gt;
&lt;li&gt;On the clean action trigger the vacuum to start a clean session&lt;/li&gt;
&lt;li&gt;On the relax action toggle the lounge scene between a cool dim mode and a warm dim mode&lt;/li&gt;
&lt;li&gt;On the bright action set the lights in the lounge to full brightness and reset the color&lt;/li&gt;
&lt;li&gt;On the all-off action switch off all the lights&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/5.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;To capture all ios events I use the events: all nodes with the event type filtering on &lt;code class=&quot;language-text&quot;&gt;ios.actions_fired&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/6.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;To branch on the event name, I use a &lt;code class=&quot;language-text&quot;&gt;switch&lt;/code&gt; node with an exit for each action name as defined in the Home Assistant app.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/7.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;To trigger the cleaning I use the &lt;code class=&quot;language-text&quot;&gt;xiaomi_miio&lt;/code&gt; service specific to Roborock and specify the rooms to clean as segments.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/8.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;To set the light scene first I use a switch to determine the current scene by checking a global variable I control, &lt;code class=&quot;language-text&quot;&gt;lounge.scene&lt;/code&gt;, then toggle the scene by calling the Home Assistant &lt;code class=&quot;language-text&quot;&gt;light.turn_on&lt;/code&gt; service with a &lt;code class=&quot;language-text&quot;&gt;call service&lt;/code&gt; node for the desired light/light group. I set the &lt;code class=&quot;language-text&quot;&gt;color_name&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;brightness_pct&lt;/code&gt; as desired. After setting each scene I then set the &lt;code class=&quot;language-text&quot;&gt;lounge.scene&lt;/code&gt; value accordingly between &lt;code class=&quot;language-text&quot;&gt;relax.warm&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;relax.cool&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/9.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/10.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;To set the full brightness I use the Home Assistant &lt;code class=&quot;language-text&quot;&gt;light.turn_on&lt;/code&gt; service with a &lt;code class=&quot;language-text&quot;&gt;call service&lt;/code&gt; node for the desired light/light group. I set the &lt;code class=&quot;language-text&quot;&gt;color_name&lt;/code&gt; to white &lt;code class=&quot;language-text&quot;&gt;brightness_pct&lt;/code&gt; to 100.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/12.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;To turn off all the lights I use the Home Assistant &lt;code class=&quot;language-text&quot;&gt;light.turn_off&lt;/code&gt; service with a &lt;code class=&quot;language-text&quot;&gt;call service node&lt;/code&gt; for the desired light/light group.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/apple-watch-actions/13.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I use the &lt;a href=&quot;https://phoscon.de/en/conbee2&quot;&gt;Conbee II&lt;/a&gt; Zigbee stick and have deCONZ setup. There I have defined light groups, for instance, I have multiple lights in the lounge set under one group so that from automation I only call the group name and not individual light names. Light groups can also be set up in Home Assistant.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;While I prefer &lt;a href=&quot;https://nodered.org/&quot;&gt;Node Red&lt;/a&gt;, this entire setup is achievable using &lt;a href=&quot;https://www.home-assistant.io/docs/automation/&quot;&gt;Home Assistant automations&lt;/a&gt; and capturing the events from there and creating actions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Test Builder Pattern]]></title><description><![CDATA[Photo by Alan Rodriguez on Unsplash While working with DTOs and entities, particularly those that are used throughout your domain and…]]></description><link>http://www.drunkonmonads.com/test_builders/</link><guid isPermaLink="false">http://www.drunkonmonads.com/test_builders/</guid><pubDate>Sat, 30 Jan 2021 10:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@alan_rodriguez?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Alan Rodriguez&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/rUtX6dvmCeM?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;While working with DTOs and entities, particularly those that are used throughout your domain and boundaries, you will find that they are required in a multitude of tests. A natural approach is to call the constructor of each when required and hydrate them with required setup. While this is very easy and straightforward there are a couple of challenges. There is always a caveat.&lt;/p&gt;
&lt;p&gt;To illustrate these challenges let us introduce an example of a simple domain object. Let’s take a dumbed down conceptual take at a financial trade position, that has an identifier and monetary values for fixed and float legs.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Investopedia defines a position as follows. A trade position is the amount of a security, commodity or currency which is owned by an individual, dealer, institution, or other fiscal entity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The TradePosition properties will be as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A unique identifier of type &lt;code class=&quot;language-text&quot;&gt;Guid&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A floating leg notional of custom type &lt;code class=&quot;language-text&quot;&gt;PositionValue&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A fixed leg notional of type &lt;code class=&quot;language-text&quot;&gt;PositionValue&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In turn the TradeValue properties will be as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A numeric value of type &lt;code class=&quot;language-text&quot;&gt;double&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;A currency iso code of type &lt;code class=&quot;language-text&quot;&gt;string&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;c#&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradeValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FixedLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradeValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FloatLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;record&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TradeValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CurrencyIsoCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now what could go wrong with the simple approach? Well the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;As your solution grows and the trade position is used in hundreds of tests you may update the domain by say adding new properties that affect the ctor. In this case you need to update a multitude of tests manually.&lt;/li&gt;
&lt;li&gt;Over time you may change the meaning of certain things in the domain. For instance if we had maturity in the trade position and furthermore in the future we may want the aspects that determine maturity to change. Any tests that were created with a &lt;em&gt;‘mature’&lt;/em&gt; trade position will also need to updated with this knowledge. This breaks a lot of principles, ideally the state and validity of an object should be self contained and if the outside has to understand inner workings to attain a given state that is a fail, and yes even for tests.&lt;/li&gt;
&lt;li&gt;In many cases you may simply want a trade position for the purposes of the test without a need for it to be in a specific state, but rather just to be valid. In this case you find code copy pasted all over the code base creating a bigger maintenance problem over time.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;Investopedia defines maturity as follows. The maturity is the date on which the principal amount of a note, draft, acceptance bond or other debt instrument becomes due.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;So, how do I solve this?&lt;/h3&gt;
&lt;p&gt;Let’s start with another very tempting pattern that I have seen often. The following is a very simple &lt;strong&gt;attempt&lt;/strong&gt; to address this problem.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;c#&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MediocreTradePositionBuilder&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CreateTradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradeValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fixedLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradeValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;floatLegNotional&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This does not really solve all the problems, or at least does so by introducing new ones. As our domain evolves and trade position/trade value grow then the method parameters here become messy. This particular case takes in TradeValue for the leg notionals, which means the test has to also build these and know about their inner workings, not great. One way around that is to accept the raw values further causing the parameters to blow up.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;c#&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MediocreTradePositionBuilder&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;CreateTradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fixedLegNotionalValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;fixedLegNotionalCurrencyIsoCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;floatLegNotionalValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;,&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;floatLegNotionalCurrencyIsoCode&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        )&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            ...&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The biggest problems with this pattern however is that it does not communicate intention or evolve well. How do I build a trade position that is mature? The answer often then lies in the test, which is not great as this is an auxiliary concern and not the intent of the test. As you can have multiple scenarios also how does this work with this pattern? One way is to add more parameters to control this, gosh 🤦. Or maybe create multiple of these methods for each scenario. With this pattern I often find this code will still be copy pasted to add the flexibility, so naturally I am not promoting this one.&lt;/p&gt;
&lt;p&gt;Finally the tests that use this pattern or none at all tend to be very long and messy to read. By looking at the code at a glance it is not possible to understand what the &lt;strong&gt;arrange&lt;/strong&gt; stage is doing, worse still it makes it hard to distinguish clearly the &lt;strong&gt;arrange&lt;/strong&gt; from the &lt;strong&gt;act&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Get to it already, show me the way&lt;/h3&gt;
&lt;p&gt;Let’s get straight to it and look at a different pattern in code.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;c#&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePositionBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePositionBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithIdentifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;identifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePositionBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithFloatLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PositionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;positionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FloatLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;positionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePositionBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithFixedLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PositionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;positionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FixedLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;positionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePositionBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ThatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FixedLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;PositionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ThatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FloatLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;PositionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ThatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;override&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Identifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FixedLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;),&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;FixedLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PositionValueBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PositionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PositionValueBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithCurrencyIsoCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;currencyIsoCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CurrencyIsoCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;currencyIsoCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PositionValueBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PositionValueBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ThatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CurrencyIsoCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;EUR&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1_500_000&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;override&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PositionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;          =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PositionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;), &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;CurrencyIsoCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;OK so why is this better? I’m glad you asked, here we go.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Communication of intent.&lt;/strong&gt; The methods we see here are very clear on what we are building and while we kept this simple, they can start to cater for scenario like a mature trade position with say ‘ThatIsMatured’ or an invalid trade with ‘ThatIsInvalid’. This makes it easy in tests especially in scenarios where the trade position is not primary to the test but still required for the scenario.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fluent.&lt;/strong&gt; Who does not love fluent code, this one makes this even easier to use and very natural to read. If there is anything you should strive for it is readable tests. Recall that when we ditched explicit documentation in code, we made an oath to write self documenting code, one of which is through tests, so they better be easy to read and understand.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Less code.&lt;/strong&gt; So if the auxiliary act of creating objects for our tests is not key to the tests why should that mess make the test hard to read? I would rather see &lt;code class=&quot;language-text&quot;&gt;var tradePosition = A.TradePosition.ThatIsMature()&lt;/code&gt; than see all the code that entails this. It is quite rare from a ‘reading through test code’ perspective that I even want to see that at all.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ease of refactoring.&lt;/strong&gt; This approach isolates the actual creation of something to one place and one place only much like a factory. So now as your domain evolves and you change the meaning of things, ctors change, etc among many change and as far as your tests are concerned this change only needs to be done in one place.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clean and simple.**&lt;/strong&gt; In particular this caters very well for scenarios were you want a valid object without need to control the actual values. Now you do not need to have this copy pasted all over the place.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s see some usage examples:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;c#&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Sample&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        [&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Fact&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// caters for the common scenario, you just need a valid trade position&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;tradePosition1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TradePosition&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;ThatIsValid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// caters for scenario were you need to be in control of all properties&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;tradePsition2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TradePosition&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithIdentifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;())&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithFixedLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// notice the chained builder here, very powerful!&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;PositionValue&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1_500_00&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithCurrencyIsoCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;EUR&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithFloatLegNotional&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                    &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;PositionValue&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2_480_00&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                        .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithCurrencyIsoCode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;EUR&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// caters for scenario where you care for single property&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;// in your test but the rest also should be valid&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;tradePosition3&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TradePosition&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;                .&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;WithIdentifier&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Guid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;NewGuid&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;());&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;All things considered we can certainly say that this is both simple and powerful. Creating the builders is easy and the pattern fosters for clean code. Using the builders is also very intuitive and the fluent pattern further makes this a pleasure to use.&lt;/p&gt;
&lt;h3&gt;Show me the guts&lt;/h3&gt;
&lt;p&gt;Let’s have a look at what is going on behind the scenes to power this and to also understand some of the calls in the builder examples.&lt;/p&gt;
&lt;p&gt;The first one is something that will not need to be changed often, if at all. You would have noticed the two builders above have a generic builder base class. The base class is as follows:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;c#&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;abstract&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;private&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;readonly&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Dictionary&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;protected&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;abstract&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;implicit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;operator&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;builder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Build&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// Temporarily hold property value&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeparam&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;TProp&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;Property type&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeparam&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;action&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;Property expression&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;value&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;Value to hold&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MemberExpression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Member&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// Get previously set value&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;summary&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeparam&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;TProp&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;Property type&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;typeparam&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;action&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;Property expression&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;/// &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;returns&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Expression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Func&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;T&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = (&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MemberExpression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;action&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Body&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;expression&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Member&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_properties&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;TryGetValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;exists&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ? &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;dynamic&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; : &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TProp&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This base class has an abstract Build method returning the generic type. What this means is that if you have &lt;code class=&quot;language-text&quot;&gt;TradePositionsBuilder: Builder\&amp;lt;TradePosition\&gt;&lt;/code&gt;, the implementation must have a build method returning a trade position. This makes sense to be enforced as that is the core purpose of the builder. More interestingly however you will notice that there is an implicit operator overload from the builder itself to the generic type that calls this build method. This allows us to use the builder and have it implicitly cast to the target type in the end, making for succinct code. An alternative would have been to explicitly call build.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Whilst this pattern is simple, effort is made here clearly to make this as powerful out of the box as possible. As this is used in the practice take care to ensure patterns are observed especially the pain points of making builders and using them and address them as you go along.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;You would have taken notice of the Get and Set methods that work with a backing dictionary. This is in place to further make creating your own builders easy. Remember that as someone uses your builder they call the fluent methods one at a time before the implicit call to build. That means the values for each property need to be saved somewhere until build is called. If you are working with mutable types like DTOs this is easy as you can create the object and set the properties for each call, however this cannot be for immutable types like domain objects and as you can guess I am promoting immutability wherever possible, so this has to be supported out of the box for my pattern. The builder can call set providing the property and value and call get providing property to get back the previously stored value. Have another look at the two builders above to see this more clearly. Behind the scenes Expressions are used to make this approach clean, easy and tied to whatever type the builder is returning via the generic use. From that the property name is used to store the values in the dictionary and to get them back all in an efficient and type safe manner.&lt;/p&gt;
&lt;p&gt;If you were paying close attention you would have noticed the readability added by the use of the &lt;code class=&quot;language-text&quot;&gt;A&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Some&lt;/code&gt; to give results like &lt;code class=&quot;language-text&quot;&gt;A.TradePosition&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;Some.PositionValue&lt;/code&gt; that conform to natural language. While optional this can be the cherry on the top to make the calls natural to read.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;c#&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;A&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePositionBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TradePosition&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TradePositionBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Some&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;static&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PositionValueBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;PositionValue&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PositionValueBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the use of &lt;code class=&quot;language-text&quot;&gt;=&gt;&lt;/code&gt; and not &lt;code class=&quot;language-text&quot;&gt;=&lt;/code&gt;. This is intentional and care must be taken to do it this way. You want to ensure that each call to this property makes a new builder. This isolation for tests is essential especially considering that the builders have state.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This pattern is very simple. However given that &lt;strong&gt;1.&lt;/strong&gt; this involves &lt;em&gt;‘only tests’&lt;/em&gt; and &lt;em&gt;2.&lt;/em&gt; the problem does not seem that complex and pressing, this tends to be highly neglected. The consequences are however dire and do not discriminate because this is only tests. The amount of time lost to go around the challenges of not handling this problem properly can be great.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That’s all folks!&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk17 { color: #808080; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Track API breaking changes in .net]]></title><description><![CDATA[Photo by Jackson Simmer on Unsplash If you have ever maintained a public API, in particular a large one, you may know just how easy it is to…]]></description><link>http://www.drunkonmonads.com/tracking-breaking-changes/</link><guid isPermaLink="false">http://www.drunkonmonads.com/tracking-breaking-changes/</guid><pubDate>Fri, 29 Jan 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@simmerdownjpg?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Jackson Simmer&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/Vqg809B-SrE?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you have ever maintained a public API, in particular a large one, you may know just how easy it is to accidentally make breaking changes and roll them out. I have found some interesting ways in the past to avoid this, but I won’t bore you with those as I found a better way. Microsoft rolled out a Roslyn Analyzer, PublicApiAnalyzers, that solves just this problem.&lt;/p&gt;
&lt;p&gt;The Analyzer works via two text files, &lt;code class=&quot;language-text&quot;&gt;PublicAPI.Unshipped.txt&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;PublicAPI.Shipped.txt&lt;/code&gt;. The analyzer once setup gives the option via Visual Studio to track certain entities as being part of the public API. This will be done by serializing as text, a representation of that entity in the PublicAPI.Unshipped.txt. How you use the PublicAPI.Shipped.txt is entirely up to you. Once you have made changes to the API you will see a warning about something not being in the public API, ideally you would choose the option to update the API details. Now each time you see a change in your pull requests that results in this file being changed it is good reflection point to check if all the API changes are safe or intended and as we will cover later, you can also fail the build on some of the changes.&lt;/p&gt;
&lt;h3&gt;Example&lt;/h3&gt;
&lt;p&gt;You will need to install the nuget package &lt;code class=&quot;language-text&quot;&gt;Microsoft.CodeAnalysis.PublicApiAnalyzers&lt;/code&gt; and manually add the two text files we discussed to your project. Ensure that the text files are added as &lt;code class=&quot;language-text&quot;&gt;AdditionalFiles&lt;/code&gt; in, this is important for the analyzer to work. Your project file should look something like this:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;xml&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Sdk&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Microsoft.NET.Sdk&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;net5.0&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;TargetFramework&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PropertyGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;AdditionalFiles&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;PublicAPI.Shipped.txt&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;AdditionalFiles&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Remove&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;PublicAPI.Unshipped.txt&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;/&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Include&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;Microsoft.CodeAnalysis.PublicApiAnalyzers&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Version&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;3.3.2&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;all&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PrivateAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;      &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;runtime; build; native; contentfiles; analyzers; buildtransitive&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;IncludeAssets&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;PackageReference&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;ItemGroup&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;Project&lt;/span&gt;&lt;span class=&quot;mtk17&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s say you had the following as part of your public API&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;namespace&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;PublicApiSample&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;{&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;using&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Collections&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Generic&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;delegate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TagsAppender&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;List&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;tagBuilder&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Metrics&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    {&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;void&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Timer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TimeSpan&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;elapsed&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TagsAppender&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NotImplementedException&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;public&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;IDisposable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Timer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TagsAppender&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            =&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;throw&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;NotImplementedException&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You will now notice a warning on the various types indicating that they are not part of the public API.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/tracking-breaking-changes/1.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;You can proceed to add everything in this document to the public API.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/tracking-breaking-changes/2.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;PublicAPI.Unshipped.txt&lt;/code&gt; file should now have the following.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;csharp&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;PublicApiSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Metrics&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;PublicApiSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Metrics&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Metrics&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;void&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;PublicApiSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Metrics&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Timer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;PublicApiSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TagsAppender&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;IDisposable&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;PublicApiSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;Metrics&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;Timer&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TimeSpan&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;elapsed&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;PublicApiSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TagsAppender&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;tags&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;void&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk12&quot;&gt;PublicApiSample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;TagsAppender&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now if you for instance blindly add a new constructor that replaces the default constructor it would be breaking the public API. You will have the warning again to add this to the public API and doing so would raise a question in the pull request.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/screenshots/tracking-breaking-changes/3.jpg&quot; alt=&quot;screenshot&quot;&gt;&lt;/p&gt;
&lt;p&gt;If again you delete the first of the two methods in the Metrics class and build the project you will have the following warning in the build output:
&lt;code class=&quot;language-text&quot;&gt;Symbol &apos;PublicApiSample.Metrics.Timer(string key, System.TimeSpan elapsed, PublicApiSample.TagsAppender tags = null) -&gt; void&apos; is part of the declared API, but is either not public or could not be found&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In addition to the IDE features, all the change scenario have warnings emitted on build. I would recommend determining which of those warnings are of interest and treating them as error instead.&lt;/p&gt;
&lt;p&gt;The following warnings are available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;RS0016: Add public types and members to the declared API&lt;/li&gt;
&lt;li&gt;RS0017: Remove deleted types and members from the declared API&lt;/li&gt;
&lt;li&gt;RS0022: Constructor make noninheritable base class inheritable&lt;/li&gt;
&lt;li&gt;RS0024: The contents of the public API files are invalid&lt;/li&gt;
&lt;li&gt;RS0025: Do not duplicate symbols in public API files&lt;/li&gt;
&lt;li&gt;RS0026: Do not add multiple public overloads with optional parameters&lt;/li&gt;
&lt;li&gt;RS0027: Public API with optional parameter(s) should have the most parameters amongst its public overloads&lt;/li&gt;
&lt;li&gt;RS0036: Annotate nullability of public types and members in the declared API&lt;/li&gt;
&lt;li&gt;RS0037: Enable tracking of nullability of reference types in the declared API&lt;/li&gt;
&lt;li&gt;RS0041: Public members should not use oblivious types&lt;/li&gt;
&lt;li&gt;RS0048: Missing shipped or unshipped public API file&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See the documentation of these warnings &lt;a href=&quot;https://github.com/dotnet/roslyn-analyzers/blob/master/src/PublicApiAnalyzers/Microsoft.CodeAnalysis.PublicApiAnalyzers.md&quot;&gt;here.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Making your builds fail on these warnings is easy. You could for example treat all the warnings as errors by adding the following to the csproj file.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;&amp;lt;WarningsAsErrors&gt;$(WarningsAsErrors);RS0016;RS0017;RS0022;RS0024;RS0025;RS0026;RS0027&amp;lt;/WarningsAsErrors&gt;&lt;/code&gt;&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk17 { color: #808080; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Dotnet Tools]]></title><description><![CDATA[Photo by Cesar Carlevarino Aragon on Unsplash Dotnet tools are not just add-ons; they are essential components that significantly enhance…]]></description><link>http://www.drunkonmonads.com/dotnet-tools/</link><guid isPermaLink="false">http://www.drunkonmonads.com/dotnet-tools/</guid><pubDate>Tue, 01 Dec 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@carlevarino?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Cesar Carlevarino Aragon&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/NL_DF0Klepc?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dotnet tools are not just add-ons; they are essential components that significantly enhance our development workflow in .NET environments. They streamline complex tasks, automate repetitive processes, and ensure consistency across our projects. In this post, I’ll share some of my favorite tools that have become indispensable in my .NET development journey. From managing dependencies to ensuring consistent coding styles, these tools are vital for any serious .NET developer looking to optimize their workflow and maintain high-quality code.&lt;/p&gt;
&lt;h3&gt;Managing references&lt;/h3&gt;
&lt;p&gt;I like to keep my projects clean and tend to prune transitive dependencies. Doing it manually, however, can be tedious. There is a tool for that. Snitch is a powerful tool for pruning unnecessary transitive dependencies in your .NET projects. It helps in identifying packages that are no longer needed, thus keeping your project clean and efficient. Especially useful in large projects, Snitch simplifies what would otherwise be a daunting task of manually sifting through dependencies.&lt;/p&gt;
&lt;p&gt;[snitch] (&lt;a href=&quot;https://github.com/spectresystems/snitch&quot;&gt;https://github.com/spectresystems/snitch&lt;/a&gt;) &lt;code class=&quot;language-text&quot;&gt;dotnet tool install -g snitch&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;In a recent large-scale project, I faced the challenge of managing an overwhelming number of dependencies. Snitch was a game-changer, identifying several unused packages that were bloating our project. By removing these, we not only streamlined our application but also reduced build times significantly.&lt;/p&gt;
&lt;h3&gt;Visualizing code coverage&lt;/h3&gt;
&lt;p&gt;I use coverlet and often need to convert the output into a human-readable format, HTML in my case. There is a tool for that. Report Generator converts coverage reports generated by Coverlet into a human-readable format like HTML. This tool is vital for visualizing which parts of your code are being tested, helping you to identify areas that need more thorough testing. It’s an essential tool for maintaining high-quality code and ensuring that your tests are as comprehensive as possible.&lt;/p&gt;
&lt;p&gt;[report generator] (&lt;a href=&quot;https://github.com/danielpalme/ReportGenerator&quot;&gt;https://github.com/danielpalme/ReportGenerator&lt;/a&gt;) &lt;code class=&quot;language-text&quot;&gt;dotnet tool install -g dotnet-reportgenerator-globaltool&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Enforcing .editorconfig&lt;/h3&gt;
&lt;p&gt;I honestly get frustrated when formatting is inconsistent, particularly when it makes me start to read through code slower. Well, how do you enforce that nice editor config you already worked on as a team? There is a tool for that. &lt;code class=&quot;language-text&quot;&gt;Dotnet-Format&lt;/code&gt; is a lifesaver when it comes to enforcing coding styles and formats. This tool automatically applies the rules specified in your &lt;code class=&quot;language-text&quot;&gt;.editorconfig&lt;/code&gt; file across your project, ensuring consistent formatting. It’s especially helpful in collaborative environments, eliminating the frustration of inconsistent coding styles among team members.&lt;/p&gt;
&lt;p&gt;[dotnet format] (&lt;a href=&quot;https://github.com/dotnet/format&quot;&gt;https://github.com/dotnet/format&lt;/a&gt;) &lt;code class=&quot;language-text&quot;&gt;dotnet tool install -g dotnet-format&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Update packages&lt;/h3&gt;
&lt;p&gt;I like dependabot but there are times when I need to do this locally as well. In particular, if say there are 10 packages to update, I would like to update 1 at a time and on each update run a dotnet clean, build and test. If all is good then move to the next. There is a tool for that.&lt;/p&gt;
&lt;p&gt;[nukeeper] (&lt;a href=&quot;https://github.com/NuKeeperDotNet/NuKeeper&quot;&gt;https://github.com/NuKeeperDotNet/NuKeeper&lt;/a&gt;) &lt;code class=&quot;language-text&quot;&gt;dotnet tool install nukeeper --global&lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For my particular use case I use the &lt;code class=&quot;language-text&quot;&gt;nukeeper update&lt;/code&gt; option. There are however more options including the ability to open pull requests for a project or entire org (only supported in GigHub)&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;In conclusion, the right set of .NET tools can make an immense difference in your development experience. They bring efficiency, consistency, and quality to your work. Whether it’s managing dependencies, ensuring code coverage, or maintaining a consistent coding style, these tools are key to a smooth and effective .NET development process. I encourage every .NET developer to explore these tools and integrate them into their workflow to experience the benefits firsthand.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Unit Testing with pytest]]></title><description><![CDATA[Photo by Hitesh Choudhary on Unsplash Unit testing is one of the most valuable tools we have as developers to ensure that we write working…]]></description><link>http://www.drunkonmonads.com/python-unit-testing/</link><guid isPermaLink="false">http://www.drunkonmonads.com/python-unit-testing/</guid><pubDate>Sat, 04 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@hiteshchoudhary?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Hitesh Choudhary&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/D9Zow2REm8U?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Unit testing is one of the most valuable tools we have as developers to ensure that we write working code. I have tried out both the inbuilt unittest and the third party pytest and no doubt have found pytest to shine. At a glance the two appear to be equal and unittest for me personally has a better assertions syntax. However when you start to do some more advanced things like fixtures and mocking then you really see pytest shine and when it comes to control of running tests you will have way more at your disposal with pytest.&lt;/p&gt;
&lt;p&gt;This article is not meant to compare the two but instead will be focused on highlighting some key features of pytest.&lt;/p&gt;
&lt;h3&gt;Sample test&lt;/h3&gt;
&lt;p&gt;Let’s look at two very simple tests&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; typing &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; NoReturn&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; pytest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;to_str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(x)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_to_str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; to_str(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) == &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;3&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;raises&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() -&amp;gt; NoReturn:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;raise&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SystemExit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_raises&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()  -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; pytest.raises(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SystemExit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        raises()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-thulani-chivandikwa/master/src/content/img/pytest_1.jpg&quot; alt=&quot;Test Result&quot;&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;For tests to be discovered they have to have the naming convention test_*&lt;/p&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;PRO TIP: If you want to continually run your tests in Pycharm as you make changes you can set the current test run to be run on a delay when you stop coding by toggling this with the auto-test icon (refresh icon). The top bar of the test runner has a settings menu item (cog wheel icon) and there you can configure the delay for values between 1 and 10 seconds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have pytest set as the default test runner in Pycharm, see screenshot below for setting. Additionally you can run this from the console with the command &lt;code&gt; pytest -q test_file.py &lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-thulani-chivandikwa/master/src/content/img/pytest_1.jpg&quot; alt=&quot;Pycharm set test runner&quot;&gt;&lt;/p&gt;
&lt;p&gt;The tests above are simple functions, alternatively they could have been grouped under a class:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;To my delight each test run by pytest in a class gets it’s own instance, which is great for isolation. Are you paying attention NUnit?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; typing &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; NoReturn&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; pytest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;to_str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(x)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;raises&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() -&amp;gt; NoReturn:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;raise&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SystemExit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;TestSamples&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_to_str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; to_str(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) == &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;3&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_raises&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; pytest.raises(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SystemExit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;            raises()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_needsfiles&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;tmpdir&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(tmpdir)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Test that creates temp files&lt;/h3&gt;
&lt;p&gt;If you are writing a test that creates temp files or any other scenario that requires a temp folder, pytest has your back, no need to jump through hoops. This can be achieved by using a parameter named tmpdir that will be fulfilled by a fixture to inject a LocalPath to your test.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; py._path.local &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; LocalPath&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_create_temp_files&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;tmpdir&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: LocalPath):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;JUnitXML&lt;/h3&gt;
&lt;p&gt;You can configure your test runs to emit the JUnit XML report that can be consumed by many Continuous Integration tools like Jenkins, providing a visual report on. This can be achieved by triggering the test run with the junitxml flag and providing output path &lt;code&gt; pytest —junitxml=path &lt;/code&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you require a human readable report you can also emit plain text by triggering with the resultlog flag and providing an output path &lt;code&gt; pytest —resultlog=path &lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Assert that an exception is raised&lt;/h3&gt;
&lt;p&gt;Asserting if an exception has been raised is straightforward with context managers&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_raises&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; pytest.raises(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SystemExit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        raises()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_raises_access_exception&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; pytest.raises(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;SystemExit&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; exc_info:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        raises()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(exc_info.typename)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Test logging&lt;/h3&gt;
&lt;p&gt;It is very common to want to test if you code is logging out as expected, this can be achieved easily with the caplog built in fixture.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; logging&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; _pytest.logging &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; LogCaptureFixture&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;get_logger&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) -&amp;gt; logging.Logger:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    logger = logging.getLogger(name)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    logger.setLevel(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;DEBUG&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; logger&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()-&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    logger = get_logger(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    logger.info(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;sample log&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_logging&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;caplog&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: LogCaptureFixture):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    log()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(caplog.messages)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(caplog.text)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(caplog.text)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(caplog.records)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(caplog.record_tuples)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    caplog.clear()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The same can be achieved with capsys for writes to sys.stdout and sys.stderr&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_sys_output&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;capsys&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: CaptureFixture):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;hello there&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    captured = capsys.readouterr()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(captured)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Mocking&lt;/h3&gt;
&lt;p&gt;This is the big one. To have complete test coverage you will no doubt have to test code that has external dependencies that you do not desire in your test or that you cannot control at all. In that case one way, is to mock the specific dependencies. The mocks can target both attributes and behavior. This is surprisingly very easy to achieve with pytest using the MonkeyPatch fixture.&lt;/p&gt;
&lt;p&gt;This fixture has support for mocking various things such as method calls, properties, dictionaries and environment variables. Here are a few examples:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; functools&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; os&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; pathlib &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Path&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; pytest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; requests&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; _pytest.monkeypatch &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; MonkeyPatch&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;get_path&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;():&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Path.home()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Mock method return value&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_get_path&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;monkeypatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: MonkeyPatch):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;mock_return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;():&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Path(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;/abc&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    monkeypatch.setattr(Path, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;home&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, mock_return)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    x = get_path()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; x == Path(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;/abc&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;get_json&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    response = requests.get(url)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; response.json()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;MockResponse&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;staticmethod&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;json&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;():&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; {&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Name&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Chloe&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Mock method return object&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_get_json&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;monkeypatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: MonkeyPatch):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;mock_get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(*&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_args&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, **&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_kwargs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; MockResponse()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    monkeypatch.setattr(requests, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;get&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, mock_get)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    result = get_json(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;https://fake&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; result[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Name&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] == &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Chloe&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Scoping of mock with context manager&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Useful as mocking certain framework aspects may break pytest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_patch_scoped&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;monkeypatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; monkeypatch.context() &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;as&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; m:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        m.setattr(functools, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;partial&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; functools.partial == &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;get_environment_variables&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;():&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    username = os.getenv(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;USER&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; username &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;raise&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;OSError&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;USER environment is not set.&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; username.lower()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Mock environment variables&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_upper_to_lower&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;monkeypatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: MonkeyPatch):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    monkeypatch.setenv(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;USER&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;TestingUser&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;assert&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; get_environment_variables() == &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;testinguser&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_raise_exception&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;monkeypatch&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: MonkeyPatch):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    monkeypatch.delenv(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;quot;USER&amp;quot;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;raising&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; pytest.raises(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;OSError&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        _ = get_environment_variables()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That is all I will cover in this post. Take a look at the pytest website for documentation and more examples &lt;a href=&quot;https://docs.pytest.org&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Pycharm hidden gems]]></title><description><![CDATA[Photo by Artturi Jalli on Unsplash Here are a few interesting features of Pycharm that are otherwise not commonly known or used. Live…]]></description><link>http://www.drunkonmonads.com/pycharm-hidden-gems/</link><guid isPermaLink="false">http://www.drunkonmonads.com/pycharm-hidden-gems/</guid><pubDate>Wed, 01 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/@artturijalli?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Artturi Jalli&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/g5_rxRjvKmg?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here are a few interesting features of Pycharm that are otherwise not commonly known or used.&lt;/p&gt;
&lt;h3&gt;Live templates&lt;/h3&gt;
&lt;p&gt;Live templates make it easy to add commonly used or otherwise annoying boiler plate code. I will not cover the existing live templates as you can have a look for yourself (File -&gt; Settings [ctrl + alt + s] -&gt; Editor -&gt; Live Templates)&lt;/p&gt;
&lt;p&gt;I do have a few custom ones to share that may be of interest to you.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# add a new sanic route&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;@app.get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;/$ROUTE$&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;async def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;ROUTE&lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(_: Request) &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; HTTPResponse:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; response.json([&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# import logger in a file&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; logging&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;logger = logging.getLogger(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# create a data class&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;@dataclass&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;NAME&lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    test: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# create a json data class&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;@dataclass_json&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;letter_case&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=LetterCase.CAMEL)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;@dataclass&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;NAME&lt;/span&gt;&lt;span class=&quot;mtk14&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    test: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Post fix autocompletion&lt;/h3&gt;
&lt;p&gt;Post fix autocompletion can make writing certain Python constructs faster. For example if you want the following&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; user.authorized:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    current_user = user&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Instead of typing &lt;code&gt; if user.authorized &lt;/code&gt;, you could type user.authorized.if and hit tab resulting in the if statement block and cursor on the next line.&lt;/p&gt;
&lt;p&gt;The other supported postfix template are:&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;a.ifn&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; a &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;a.ifnn&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; a &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;a.len&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(a)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;).main&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;abs&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;a.&lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;not&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;a.print&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(a)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;a.&lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;a.&lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;while&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; a:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;To my disappointment Pycharm currently does not support the adding new post fix template targetting python, but somehow does for SQL.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;File Templates&lt;/h3&gt;
&lt;p&gt;File templates are a sort of specification for the default contents of new files you create. Adding your own for the commonly bootstrapped files types can really increase your creativity.&lt;/p&gt;
&lt;p&gt;Adding/Editing is easy (File -&gt; Settings [ctrl + alt + s] -&gt; Editor -&gt; File and Code Templates)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-thulani-chivandikwa/master/src/content/img/pycharm_file_templates.png&quot; alt=&quot;settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here are a few examples for context.&lt;/p&gt;
&lt;p&gt;Bootstrap a new new unit test file&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; unittest&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;#[[$Title$]]#Tests(unittest.TestCase):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test_x_given_when_then&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.assertEqual(&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;False&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    unittest.main()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Bootstrap a new sanic api&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; logging&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; sanic &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Sanic, response&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; sanic.request &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Request&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; sanic.response &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; HTTPResponse&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; sanic_openapi &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; doc, swagger_blueprint&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; sanic_openapi.doc &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; summary&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;logger = logging.getLogger(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;app = Sanic(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;app.logger = logger&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;app.blueprint(swagger_blueprint)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;app.config[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;API_SCHEMES&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;http&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;https&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;app.config[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;API_TITLE&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = APP_NAME&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;app.config[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;API_DESCRIPTION&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;@summary&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;@doc.produces&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(doc.List(doc.String))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;@app.get&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;/test&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;test&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: Request) -&amp;gt; HTTPResponse:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; response.json([&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;__name__&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; == &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    app.run(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=HOST, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;port&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=PORT, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;threaded&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;api&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() -&amp;gt; Sanic:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; app&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk14 { color: #F44747; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[Python type hints]]></title><description><![CDATA[Photo by Javier Allegue Barros on Unsplash This is my hopefully simple to follow Python type hints primer. I will only cover a few of the…]]></description><link>http://www.drunkonmonads.com/python-type-hints/</link><guid isPermaLink="false">http://www.drunkonmonads.com/python-type-hints/</guid><pubDate>Wed, 01 Apr 2020 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Photo by &lt;a href=&quot;https://unsplash.com/pt-br/@soymeraki?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Javier Allegue Barros&lt;/a&gt; on &lt;a href=&quot;https://unsplash.com/photos/C7B-ExXpOIE?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText&quot;&gt;Unsplash&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is my hopefully simple to follow Python type hints primer. I will only cover a few of the common types hints that should get a beginner started.&lt;/p&gt;
&lt;p&gt;Type hints are Pythons formal solution to statically indicate the types of variables. This is however not used by the python runtime in most cases but can be useful for type checkers, IDEs, linters etc.&lt;/p&gt;
&lt;h3&gt;Built in types&lt;/h3&gt;
&lt;p&gt;Any type, built in or user defined can be used as a type hint. Below are some of the common built in types.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;0&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;integer: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;float_value: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10.5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;boolean: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;bool&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;True&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;string: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;hello there&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;byte_array: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;bytearray&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;bytearray&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;bytes_value: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;complex_number: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;complex&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;complex&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;mapping: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;dict&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = {&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# an immutable unordered collection of unique elements&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;frozen_set: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;frozenset&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;frozenset&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# mutable sequence&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;list_collection: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = [&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;memory_view: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;memoryview&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;memoryview&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;bytearray&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# the most base type&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;object_value: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# n unordered collection of unique elements&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;set_collection: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = {&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# immutable sequence&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;tuple_collection: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;tuple&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;type_value: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(integer)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# a zip object whose .__next__() method returns a tuple where&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# the i-th element comes from the i-th iterable argument&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;zip_object: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;], [&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;A&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;B&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# the enumerate object yields pairs containing a count (from start, which&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# defaults to zero) and a value yielded by the iterable argument&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;enumerate_object: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;enumerate&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;])&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Any&lt;/h3&gt;
&lt;p&gt;This is the ‘catch all’ type hint you should avoid using unless in the process of porting code to support type hints. This simply means the variable/argument can be of any type.&lt;/p&gt;
&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;Any is compatible with every type.&lt;/li&gt;
&lt;li&gt;Any assumed to have all methods.&lt;/li&gt;
&lt;li&gt;All values assumed to be instances of Any.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;object is superficially similar to Any at a glance but different. Object is the root of Python’s metaclass hierarchy but is still restrictive in that the only methods you are permitted to call are ones that are a part of the object definition, unlike Any. Any is an escape hatch meant to allow you to mix together dynamic and statically typed code.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;1&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; typing &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Any&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# variable can be assigned to any type&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;unconstrained: Any&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;unconstrained = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# argument passed can be of any type&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# and method can return any type&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;unconstrained&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: Any) -&amp;gt; Any:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;pass&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;NoReturn&lt;/h3&gt;
&lt;p&gt;Special type indicating that a function never returns as in case of function that loops infinitely or always raises an exception.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;This type is invalid in other positions, e.g., &lt;code&gt;List[NoReturn]&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;2&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; typing &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; NoReturn&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# this will never return&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;raise_always&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;() -&amp;gt; NoReturn:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;raise&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;RuntimeError&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;()&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Callable&lt;/h3&gt;
&lt;p&gt;Reference to a function or lambda that can be called.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;3&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; typing &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Callable&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;to_int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;) -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(value)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# constrained callable accepting one string arg and return integer&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;convert_to_int: Callable[[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;], &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = to_int&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# unconstrained callable accepting any number of args of any type and returning any&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;double: Callable = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: x * &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# return type constrained callable accepting any number of args of any type and return nothing&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;print_out: Callable[..., &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;lambda&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(x)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;print_out(double(convert_to_int(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;250&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# 500&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;callable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(convert_to_int))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;callable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(double))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;callable&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(print_out))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# True&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# True&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# True&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;ClassVar&lt;/h3&gt;
&lt;p&gt;Marks class variables (static).&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;4&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; typing &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; ClassVar&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Sample&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    name: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    nationality: ClassVar[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;World Citizen&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# class variable&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;.name = name&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;sample = Sample(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;Shingayi&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;Sample.nationality = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;World Citizen&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(sample.nationality)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# World Citizen&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;TypeVar&lt;/h3&gt;
&lt;p&gt;Allows for creation of generic variable, useful for generic methods.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;T = TypeVar(‘T’) # Can be anything
A = TypeVar(‘A’, str, bytes) # Must be str or bytes&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;5&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; typing &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; TypeVar, Sequence, Callable, Mapping&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# unconstrained generic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;T = TypeVar(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;T&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;pass_through&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: T) -&amp;gt; T:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;input&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# constrained generic&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;U = TypeVar(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;U&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;float&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;double&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: U) -&amp;gt; U:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; * &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(double(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk11&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(double(&lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5.0&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;))&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# 10&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# 10.0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# multiple generics&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;K = TypeVar(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;K&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;V = TypeVar(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;V&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;group_by&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;items&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: Sequence[V], &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;key_func&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: Callable[[V], K]) -&amp;gt; Mapping[K, V]:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;pass&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Literal&lt;/h3&gt;
&lt;p&gt;A type that can be used to indicate to type checkers that the corresponding variable or function parameter has a value equivalent to the provided literal (or one of several literals).&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;6&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; typing &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Literal&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;MODE = Literal[&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;rb&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;wb&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;def&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk11&quot;&gt;open_file&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk12&quot;&gt;mode&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;: MODE) -&amp;gt; &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;:&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;pass&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;open_file(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;r&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;open_file(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;x&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)  &lt;/span&gt;&lt;span class=&quot;mtk3&quot;&gt;# warning expected Literal[&amp;#39;r&amp;#39;, &amp;#39;rb&amp;#39;, &amp;#39;w&amp;#39;, &amp;#39;wb&amp;#39;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Generic&lt;/h3&gt;
&lt;p&gt;The abstract base class for creating generic types.&lt;/p&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;7&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; typing &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Generic, TypeVar&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;K = TypeVar(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;K&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;V = TypeVar(&lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;V&amp;#39;&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk4&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;Mapping&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;(Generic[K, V]):&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;pass&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Optional&lt;/h3&gt;
&lt;p&gt;Optional type that can be a specific type or None.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Optional[X] is equivalent to Union[X, None]&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;8&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; typing &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Optional, Union&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;can_be_none: Optional[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;cannot_be_none: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk8&quot;&gt;&amp;#39;hi there&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;sample: Optional[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# is same as&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;sample2: Union[&lt;/span&gt;&lt;span class=&quot;mtk4&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Tuple&lt;/h3&gt;
&lt;p&gt;Tuple definition type.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Deprecated since version 3.9: builtins.tuple now supports []&lt;/p&gt;
&lt;/blockquote&gt;
&lt;pre class=&quot;grvsc-container dark-default-dark&quot; data-language=&quot;python&quot; data-index=&quot;9&quot;&gt;&lt;code class=&quot;grvsc-code&quot;&gt;&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk15&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; typing &lt;/span&gt;&lt;span class=&quot;mtk15&quot;&gt;import&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; Tuple&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Tuple of two ints&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;sample: Tuple[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;] = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# same as, but more expressive&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;sample2: Tuple = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# same as, not expressive also&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;sample3: &lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;tuple&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt; = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk3&quot;&gt;# Variable length tuple with items of homogenous type (int in this case)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;span class=&quot;mtk1&quot;&gt;sample: Tuple[&lt;/span&gt;&lt;span class=&quot;mtk10&quot;&gt;int&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, ...] = &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;mtk1&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;mtk7&quot;&gt;20&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;grvsc-line&quot;&gt;&lt;span class=&quot;grvsc-source&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
  .dark-default-dark {
    background-color: #1E1E1E;
    color: #D4D4D4;
  }
  .dark-default-dark .mtk1 { color: #D4D4D4; }
  .dark-default-dark .mtk10 { color: #4EC9B0; }
  .dark-default-dark .mtk7 { color: #B5CEA8; }
  .dark-default-dark .mtk4 { color: #569CD6; }
  .dark-default-dark .mtk8 { color: #CE9178; }
  .dark-default-dark .mtk3 { color: #6A9955; }
  .dark-default-dark .mtk11 { color: #DCDCAA; }
  .dark-default-dark .mtk15 { color: #C586C0; }
  .dark-default-dark .mtk12 { color: #9CDCFE; }
  .dark-default-dark .grvsc-line-highlighted::before {
    background-color: var(--grvsc-line-highlighted-background-color, rgba(255, 255, 255, 0.1));
    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, rgba(255, 255, 255, 0.5));
  }
&lt;/style&gt;</content:encoded></item><item><title><![CDATA[NDC Oslo 2018]]></title><description><![CDATA[I was fortunate to be able to attend this year’s NDC Oslo in the heart of Norway at Spektrum. Overall I enjoyed the line up and prospect of…]]></description><link>http://www.drunkonmonads.com/ndc-oslo-2018/</link><guid isPermaLink="false">http://www.drunkonmonads.com/ndc-oslo-2018/</guid><pubDate>Sat, 29 Dec 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I was fortunate to be able to attend this year’s NDC Oslo in the heart of Norway at Spektrum. Overall I enjoyed the line up and prospect of socializing with attendies and the various companies that had stands available. I would like to share some of my experiences there with regards mainly to the talks I attended but also other interesting things that happened outside of the auditoriums.&lt;/p&gt;
&lt;h2&gt;Key Note - A penny for every object - Mads Torgersen&lt;/h2&gt;
&lt;p&gt;Mads Torgersen, the lead designer for the C# language gave an interesting key note titled ‘A penny for every object’. He spoke about the history of object oriented programming going through all the pioneer languages and how each had a unique take that infleunced the next generation of langauges and how this evolved over time. While I like most people I had chats to afterwards found some parts of the talk to be very denses, especially on code examples in various languages the talk had a great take away message. The message being that OOP has had a great 50 years so far and it is exciting to have to see what comes in the next 50 years. Mads emphasized that while functional languages are gaining more and more attention it may not be about which one is best but the best outcome would be for the two worlds to be able to work together. Mads sentiment on the topic of functional programming considering the changes we have been seeing in C# over the last releases that highly embrace functional programming. Unless you are truly curios for details on key languages along the evolution timeline of OOP and some of the biggest regrets along the way there is not much else to get from this talk.&lt;/p&gt;
&lt;h2&gt;Clean Architecture in .net core - Ian Cooper&lt;/h2&gt;
&lt;p&gt;While this promised to be a great presentation it fell through the floor for me in that this was a very opinionated approach to Clean Architecture making use of Brighter. Don’t get me wrong, not to say brighter is not a good library. The approach makes use of the Command approach with a command dispatcher for implementing ports. This further uses the ‘Russian doll’ model (using brighter library) to allow a pipeline of handlers to operate on a command. This is a very interesting approach and definitely has it’s merits. Furthermore brighter implements:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Task queues allowing for offloading and handling of requests asynchornously.&lt;/li&gt;
&lt;li&gt;CQRS&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The brighter library source code is available on Github &lt;a href=&quot;https://github.com/BrighterCommand/Brighter&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;At the end of the day Brighter pretty much achieves the same as most projects at Coolblue. There is a queue receiving messages with subscriber registries in place that route to a request handler registry in place to map messages to a specific request handler. The plumbing includes an IOC container, logging and Polly for retry and circuit breaker policies. This is all done in what appears to me to be a very opinionated and rigid approach in terms of the consuming. Going through the brighter documentation was still good as they definitely touch on the major things you need to deal with when working with Clean Architecture and CQRS for micro services albeit showing their approach to these problems. You can find the complete documentation &lt;a href=&quot;https://paramore.readthedocs.io/en/latest/&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Monitoring A-Z - Steven Simpson&lt;/h2&gt;
&lt;p&gt;This talk about monitoring was a little 101 than I expected and explains why a third of the room walked out in the first half an hour. I however appreciated the refresher course this provide. There is not much new things to share on this topic as I find Coolblue to be very mature in this regard and there is continued improvement. These are some of the key things this talk touched on in case you are interested at seeing the talk:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Monitoring and logging terminology&lt;/li&gt;
&lt;li&gt;Approches to monitoring and logging&lt;/li&gt;
&lt;li&gt;Local files&lt;/li&gt;
&lt;li&gt;External servers&lt;/li&gt;
&lt;li&gt;Use of databases&lt;/li&gt;
&lt;li&gt;Structured logging and searches&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;The state of C#, what have I missed - Felip Ekberg&lt;/h2&gt;
&lt;p&gt;In this talk Felip went over the iteration of the C# language, looking at the key features of each release. In his talk he also focuses on the C# 7.1, 7.2, 8.0 and beyond. For each release and feature there were code sample on show which you can find &lt;a href=&quot;https://github.com/fekberg/What-is-New-in-CSharp&quot;&gt;here&lt;/a&gt;. I will not list the features that he spoke of as the are in the samples repo and public knowledge. If you have not yet seen upcoming features like Ranges, Nullable references, Tuple improvements, deconstruction and recursive patterns be show to have look at the C# 7.x to 8.0 specific samples. To track C# 8 feature statuses have a look &lt;a href=&quot;https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Aside from language features Felip also talks about how the benefits of Microsoft having open sourced Rosylyn are really starting to show with the number of contributors and what it has meant to the development of the language.&lt;/p&gt;
&lt;p&gt;Felip recently made his C# book, Smorgasbord free which you can find here &lt;a href=&quot;https://cdn.filipekberg.se/fekberg-blog/csharp-smorgasbord-free/Filip_Ekberg-CSharp_Smorgasbord.pdf&quot;&gt;PDF&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;C# 8 - Jon Skeet and Mads Torgersen&lt;/h2&gt;
&lt;p&gt;As one would expect with Jon Skeet giving a talk this one had a full attendance with people sitting on the corridor steps. This talk was very reassuring in showing how the C# team is really becoming more pragmatic than dogmatic. It is worth noting that some of the features discussed in this talk may not actually make it to the official C# 8 release or may be modified.&lt;/p&gt;
&lt;h3&gt;Nullable reference types&lt;/h3&gt;
&lt;p&gt;A very interesting feature I was looking forward to seeing was the nullable reference types. While I had read the proposed feature list I had not dug into the details and it was a pleasure to get the details first hand. For more details on this feature and the ability to install the preview head over &lt;a href=&quot;https://github.com/dotnet/csharplang/wiki/Nullable-Reference-Types-Preview&quot;&gt;here&lt;/a&gt;. Because this feature introduces a breaking change, it would be rolled out with an opt in flag.&lt;/p&gt;
&lt;h3&gt;Pattern matching&lt;/h3&gt;
&lt;p&gt;Pattern matching is getting new improvements to the switch statements extending on pattern matching released in C#7. This one warrants a details explanation, you can find details of the proposal &lt;a href=&quot;https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Ranges&lt;/h3&gt;
&lt;p&gt;A feature that will allow for writing of powerful slicing syntax on enumerables.
To track C#8 feature statuses have a look &lt;a href=&quot;https://github.com/dotnet/roslyn/blob/main/docs/Language%20Feature%20Status.md&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Other cool things&lt;/h2&gt;
&lt;p&gt;While I probably was in an auditorium 90% of there time there was a talk going on I did try utilize all the time in between and when no talk interested me. There were a lot of booths up from various companies where you could go over and have a chat about new technologies and try out some of their prototypes. There were a lot of stands simply enticing people with challenges to play video games with possibility of winning a prize if you maintain high score. I felt really sad after this seeing how ridiculous my high scores where relative to others. FIFA 18 was off course there to the rescue as I managed to win all my attempts. The really fun part though was chatting with people and getting to know what they work with and what part of the conference they are really enjoying.&lt;/p&gt;
&lt;p&gt;I was fortunate to bump into Jon Skeet in the corridors and continue a chuckle that I had started with him on Twitter about how choice of pants the previous day and boy where the ones on that day even worse! Don’t believe me? See for yourself below. I did not get a chance to talk much with him as it was a few minutes before his talk, however it was great to meet the stack overflow man in person.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/clean/used/skeet.jpg&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;I waited eagerly to have a chat with Richard Campbell, the host of .NET Rocks after his presentation. He had given a talk about the history of .net and we had a follow up conversation on that. I was really intrigued about his story telling abilities and how he manages to engage an audience after that talk and got to talk more about that. Looking forward to the publishing of his book on the same topic in year of so as he promised. As someone who has a great relationship with many of the key players at Microsoft, this book promises to have quite some interesting stories.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/clean/used/campbell.jpg&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;Another notable speaker I got to meet after talks where Venkat Subramaniam. Venkat is a professor at the University of Houston and author of the book &lt;a href=&quot;https://pragprog.com/titles/ves6/rediscovering-javascript/&quot;&gt;Rediscovering Javascript&lt;/a&gt;. He had just given a talk title ‘Javascript - The good parts’. I was very excited to see some of the new features in Javascript that really make it much better to work with and like C# many that further embrace functional approaches. What drew me to chat with Venkat however was to complement him for an engaging talk with an interestingly unique presentation style that adds more fine to the class Microsoft live demo approach and to request for his contact details. I intend to follow up with Venkat and know more about his presentation style and giving talks in general. Hint: I intend to also start giving talks soon, starting small.&lt;/p&gt;
&lt;h2&gt;The really cool things&lt;/h2&gt;
&lt;p&gt;To really make my trip complete I ensured that I used every opportunity outside of the NDC programme to see the city of Oslo. The weather was perfect and it really is a lovely city. It was a relief to see some mountains for a change after being in The Netherlands for 7 months. Oslo may just be learning a thing or two from Rotterdam architecture as there are a lot of interesting and new building up plus a whole project in place to redefine the city and particularly water fronts. Everything is a bit pricey out there but all worth the extra penny.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/clean/used/screen.jpg&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://raw.githubusercontent.com/chivandikwa/gatsby-casper/master/src/content/img/clean/used/ndc.jpg&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;style class=&quot;grvsc-styles&quot;&gt;
  .grvsc-container {
    overflow: auto;
    position: relative;
    -webkit-overflow-scrolling: touch;
    padding-top: 1rem;
    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));
    padding-bottom: 1rem;
    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));
    border-radius: 8px;
    border-radius: var(--grvsc-border-radius, 8px);
    font-feature-settings: normal;
    line-height: 1.4;
  }
  
  .grvsc-code {
    display: table;
  }
  
  .grvsc-line {
    display: table-row;
    box-sizing: border-box;
    width: 100%;
    position: relative;
  }
  
  .grvsc-line &gt; * {
    position: relative;
  }
  
  .grvsc-gutter-pad {
    display: table-cell;
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  .grvsc-gutter {
    display: table-cell;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter::before {
    content: attr(data-content);
  }
  
  .grvsc-source {
    display: table-cell;
    padding-left: 1.5rem;
    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));
    padding-right: 1.5rem;
    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));
  }
  
  .grvsc-source:empty::after {
    content: &apos; &apos;;
    -webkit-user-select: none;
    -moz-user-select: none;
    user-select: none;
  }
  
  .grvsc-gutter + .grvsc-source {
    padding-left: 0.75rem;
    padding-left: calc(var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem)) / 2);
  }
  
  /* Line transformer styles */
  
  .grvsc-has-line-highlighting &gt; .grvsc-code &gt; .grvsc-line::before {
    content: &apos; &apos;;
    position: absolute;
    width: 100%;
  }
  
  .grvsc-line-diff-add::before {
    background-color: var(--grvsc-line-diff-add-background-color, rgba(0, 255, 60, 0.2));
  }
  
  .grvsc-line-diff-del::before {
    background-color: var(--grvsc-line-diff-del-background-color, rgba(255, 0, 20, 0.2));
  }
  
  .grvsc-line-number {
    padding: 0 2px;
    text-align: right;
    opacity: 0.7;
  }
  
&lt;/style&gt;</content:encoded></item></channel></rss>