<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Philippe Vaillancourt</title>
    <description>The latest articles on Forem by Philippe Vaillancourt (@snowfrogdev).</description>
    <link>https://forem.com/snowfrogdev</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F74189%2Ffb8260df-a6f3-4636-a829-f14285cb709e.png</url>
      <title>Forem: Philippe Vaillancourt</title>
      <link>https://forem.com/snowfrogdev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/snowfrogdev"/>
    <language>en</language>
    <item>
      <title>Vite Tips: Conditional Configs and Aliases</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Mon, 02 Sep 2024 16:06:13 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/vite-tips-conditional-configs-and-aliases-3cf8</link>
      <guid>https://forem.com/snowfrogdev/vite-tips-conditional-configs-and-aliases-3cf8</guid>
      <description>&lt;p&gt;When it comes to front-end development, especially for game jams like JS13k, having a streamlined build process is crucial. In this post, we’ll explore how to leverage Vite, a modern front-end build tool, to optimize your development workflow. We’ll dive into what Vite is, introduce JS13k and LittleJS, and show you how to use Vite's conditional configuration and resolve aliases, with code examples, to get the most out of your development setup.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/y_-FFMlbAUU"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Vite?
&lt;/h2&gt;

&lt;p&gt;Vite is a fast, opinionated build tool designed to provide a smoother development experience. Unlike traditional tools like Webpack, Vite offers a lightning-fast development server with hot module reloading (HMR) out of the box. It’s designed to be minimalistic, with great defaults, but also highly configurable to suit more advanced needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is JS13k?
&lt;/h2&gt;

&lt;p&gt;JS13k is an annual game jam where developers are challenged to create web-based games that must fit within a 13 kilobyte zip file. This strict size limit pushes developers to write extremely efficient code, often resorting to creative ways to reduce the size of their game assets and code.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is LittleJS?
&lt;/h2&gt;

&lt;p&gt;LittleJS is a lightweight JavaScript game engine designed to help developers build small, performant games for the web. It’s particularly popular in competitions like JS13k because of its small footprint and efficiency. LittleJS provides all the basics you need to get a game up and running, while still being small enough to help you meet those tight JS13k size constraints.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Conditional Configuration in Vite
&lt;/h2&gt;

&lt;p&gt;One of Vite’s powerful features is its ability to handle conditional configurations. This is particularly useful when you need different settings for development and production builds. For example, you might want to use a debug version of a library during development but switch to a minified version for production.&lt;/p&gt;

&lt;p&gt;Here’s how you can set up conditional configuration in Vite, using TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;littlejsengine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;littlejs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;esm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;
          : dist/littlejs.esm.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// Other configurations can go here...&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we use Vite’s defineConfig function to set up different configurations based on the build mode (development or production). The mode parameter allows us to determine which version of LittleJS to use. The debug version (littlejs.esm.js) is used in development, providing useful console logs and assertions, while the minified version (littlejs.esm.min.js) is used in production to keep the final bundle size as small as possible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using Resolve Aliases in Vite
&lt;/h2&gt;

&lt;p&gt;Resolve aliases in Vite allow you to remap module imports, making it easier to switch between different versions of a library or package. This feature is particularly useful in cases where a package provides multiple builds (e.g., debug vs. production versions).&lt;/p&gt;

&lt;p&gt;Continuing from the previous example, the resolve.alias field in Vite’s configuration is where you can set up these aliases. Here’s how it works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;defineConfig&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nf"&gt;defineConfig&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;littlejsengine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mode&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;dist&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nx"&gt;littlejs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;esm&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;
          : dist/littlejs.esm.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="c1"&gt;// Other configurations can go here...&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, any time you import LittleJS in your code, Vite will use the path specified in the alias. This is incredibly useful when you want to enforce the use of a specific build of LittleJS across your project without having to change import statements throughout your codebase.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why These Features Matter
&lt;/h2&gt;

&lt;p&gt;For a competition like JS13k, every byte counts. By using conditional configuration and resolve aliases, you can ensure that your development environment is optimized for debugging, while your production builds are as small as possible. This not only helps you meet the strict size limits of JS13k but also improves the overall performance of your game.&lt;/p&gt;

&lt;p&gt;Vite’s flexibility allows you to easily switch between different configurations, making your workflow smoother and more efficient. Whether you’re working on a small game for JS13k or a larger project, these features can save you time and headaches.&lt;/p&gt;

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

&lt;p&gt;Vite is a powerful tool that, when used effectively, can greatly enhance your development process. By mastering conditional configurations and resolve aliases, you can ensure that your projects are optimized for both development and production environments. And when combined with tools like LittleJS, Vite becomes an essential part of your game development toolkit, especially for challenges like JS13k.&lt;/p&gt;

&lt;p&gt;So, dive into Vite, explore its capabilities, and start building faster, more efficient games today!&lt;/p&gt;

</description>
      <category>vite</category>
      <category>js13k</category>
      <category>gamedev</category>
      <category>webdev</category>
    </item>
    <item>
      <title>The Problem with Eating an Elephant One Bite at a Time</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Mon, 19 Aug 2024 20:03:32 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/the-problem-with-eating-an-elephant-one-bite-at-a-time-10a3</link>
      <guid>https://forem.com/snowfrogdev/the-problem-with-eating-an-elephant-one-bite-at-a-time-10a3</guid>
      <description>&lt;p&gt;You've probably heard it before: when faced with a massive task, someone will inevitably try to motivate you with the famous phrase, "You eat an elephant one bite at a time."&lt;/p&gt;

&lt;p&gt;But here's the thing—I call b.s. on this metaphor. While it sounds comforting, it falls apart when applied to truly big, daunting tasks. We're not talking about something you can knock out in a day or two; we're talking about multi-week, month, or even year-long projects. The "eating an elephant" metaphor isn't just unhelpful for such projects—it actually highlights the problems with tackling them "one bite at a time."&lt;/p&gt;

&lt;p&gt;Let's break it down. An average male African elephant weighs around 6,000 kilograms (13,227 pounds). A typical bite of food might weigh about 15 grams (0.033 pounds)—roughly the size of a small piece of steak. So, we're talking about 400,000 bites to eat the entire elephant.&lt;/p&gt;

&lt;p&gt;Now, if each meal consists of 50 bites, it would take 8,000 meals to finish the elephant. At three meals a day, that's 2,700 days, or 7.3 years, of eating nothing but elephant for breakfast, lunch, and dinner. That’s an overwhelming thought.&lt;/p&gt;

&lt;p&gt;The trouble is, when people use the "eat an elephant a bite at a time" expression, they imply that you can tackle a huge project by doing a little bit here and there, fitting it in with everything else going on in your life. "Just get started," they say, "do a little bit whenever you have time, and you'll eventually get it done." But that works for a 20 oz. steak, not for an elephant.&lt;/p&gt;

&lt;p&gt;Now, imagine if you only ate elephant for dinner. That would stretch the timeline to 22 years. And if only a third of your dinner was elephant, with the rest being mashed potatoes and salad, now we're talking 66 years.&lt;/p&gt;

&lt;p&gt;Are you really going to keep an elephant carcass around for 66 years, slowly chipping away at it? Probably not. Even if you froze it, would you still want to eat 66-year-old elephant meat? And think about the logistics: the size of the freezer you'd need, the hassle of thawing it every time you wanted a few bites. It's ridiculous.&lt;/p&gt;

&lt;p&gt;But here's the thing—this metaphor, despite its flaws, does have its place in certain contexts. It’s also used to emphasize the importance of breaking down overwhelming tasks into smaller, manageable parts, and this approach can be effective. However, for large, complex projects, the metaphor oversimplifies the reality of what’s required.&lt;/p&gt;

&lt;p&gt;For truly big endeavors, the "one bite at a time" approach often leads to a slow, sporadic progress that doesn’t account for the psychological and practical challenges involved. Big projects have an expiration date—after 66 years, that book, app, or video game you’re working on might not be relevant anymore. They also take up mental space and add a cognitive load. Constantly switching back and forth between tasks comes with significant costs, making it harder to maintain momentum.&lt;/p&gt;

&lt;p&gt;You'll find plenty of advice urging you to "finish something," and it's true—completing a project has enormous benefits. But the odds of finishing something substantial by just taking a bite here and there, mixed in with your other tasks, are slim.&lt;/p&gt;

&lt;p&gt;So, how do you eat an elephant? You clear the kitchen. Get rid of the ice cream, pizza, and cucumbers—anything that isn't elephant. You focus. You put your head down and eat elephant all day, every day, until it's done.&lt;/p&gt;

&lt;p&gt;Sometimes the only way forward is full immersion, intense focus, and a relentless commitment to the task at hand. Just remember to chew between bites.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>sideprojects</category>
      <category>motivation</category>
    </item>
    <item>
      <title>Balancing Form and Function: What Tiny Glade Teaches Us</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Fri, 31 May 2024 17:02:15 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/balancing-form-and-function-what-tiny-glade-teaches-us-129l</link>
      <guid>https://forem.com/snowfrogdev/balancing-form-and-function-what-tiny-glade-teaches-us-129l</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--slTnWQYX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2024/05/pablo--11-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--slTnWQYX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2024/05/pablo--11-.png" alt="Balancing Form and Function: What Tiny Glade Teaches Us" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I just downloaded the demo for a wonderful little game called Tiny Glade. "Game" might not even be the right term to describe this interesting piece of software. Here’s how it introduces itself:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tiny Glade is a relaxing game where you doodle whimsical castles, cozy cottages and romantic ruins. There's no management, combat or goals. Just kick back and turn forgotten meadows into lovable dioramas.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QHeSv6w9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2024/05/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QHeSv6w9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2024/05/image.png" alt="Tiny Glade's welcome screen" width="800" height="707"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After spending some time with Tiny Glade, I am impressed by the level of care the developers have put into it. The attention to detail is remarkable. Every interaction feels organic and fluid, thanks to numerous subtle features.&lt;/p&gt;

&lt;p&gt;At its core, Tiny Glade is a castle-builder sandbox. You construct castles by laying down building blocks that can be translated, rotated, scaled, and joined. Essentially, it's a graphics editor like Blender or Illustrator, but much more enjoyable, especially for first-time users. Why? Because Tiny Glade focuses on form as much as function.&lt;/p&gt;

&lt;p&gt;The game’s emphasis on form does not come at the expense of function. It offers great flexibility while maintaining a natural and intuitive feel. Every action has a corresponding visual or sound effect, enhancing the experience without being overwhelming. This level of craftsmanship makes interactions pleasing.&lt;/p&gt;

&lt;p&gt;Words can't really do it justice, so here's a gameplay trailer video.&lt;/p&gt;

&lt;p&gt;This experience made me question why the applications we use daily don’t offer the same level of enjoyment. Many business applications prioritize function over form, resulting in user frustration. Product owners often justify this by citing monetary reasons, implying that investing in form is a waste. But Tiny Glade proves otherwise.&lt;/p&gt;

&lt;p&gt;As software developers, we should recognize the intrinsic value in form. People are willing to pay for pleasant interactions with software. While the balance between form and function varies by application, it is clear that focusing solely on function might be costing us more than we realize. I'm confident that &lt;a href="https://pouncelight.games/tiny-glade/"&gt;Tiny Glade&lt;/a&gt; will show that enhancing user experience can lead to commercial success.&lt;/p&gt;

</description>
      <category>design</category>
      <category>uiux</category>
    </item>
    <item>
      <title>Quick and easy local web server</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Mon, 17 Jan 2022 22:26:11 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/quick-and-easy-local-web-server-2e15</link>
      <guid>https://forem.com/snowfrogdev/quick-and-easy-local-web-server-2e15</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JF7RKqhT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2022/01/carbon--1-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JF7RKqhT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2022/01/carbon--1-.png" alt="Quick and easy local web server" width="738" height="410"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was working on the documentation for some of my open source libraries this week (&lt;a href="https://snowfrogdev.github.io/snowfrogdev/option/"&gt;@snowfrog/option&lt;/a&gt; and &lt;a href="https://snowfrogdev.github.io/snowfrogdev/result/"&gt;@snowfrog/result&lt;/a&gt;, check them out) and found myself wanting to quickly serve the documentation websites locally.  &lt;/p&gt;

&lt;p&gt;I'm using TypeDoc, which parses your TypeScript code and generates an entire API documentation website pretty much automatically. But seeing as it's an actual website and not just a simple static html file, you can't just open index.html in your browser and have the whole thing work. You need to actually serve the site with a web server.  &lt;/p&gt;

&lt;p&gt;Now I know there are different options out there for doing that, some are even integrated with your favourite IDEs and code editors. But this week I have found a way to do this that is amazingly simple and works from the command line; so it works no matter what you're doing and which software you are using in the moment.  &lt;/p&gt;

&lt;p&gt;All you need is to have Python 3 installed on your machine - you probably have it, if not here's a download link. Then, simply run the following command from the folder where your index.html is located:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python -m http.server 4200

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

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;4200&lt;/code&gt; here is the port number, you can make that whatever you want. For more information, here is a link the &lt;a href="https://docs.python.org/3/library/http.server.html#module-http.server"&gt;documentation for this Python http server module&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>server</category>
    </item>
    <item>
      <title>Break out command object</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Tue, 07 Sep 2021 12:56:29 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/break-out-command-object-3h0b</link>
      <guid>https://forem.com/snowfrogdev/break-out-command-object-3h0b</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Wy1YwL_G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/09/pablo--42-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Wy1YwL_G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/09/pablo--42-.png" alt="Break out command object" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In many applications, long functions are very hard to work with. In a legacy codebase, they are often contained in large classes that have many dependencies. The work that it takes to bring such functions and classes into a test harness is often significant and may even be overkill for the changes you need to make.&lt;/p&gt;

&lt;p&gt;If the function that you need to work with is large or uses instance variables and functions, consider using &lt;em&gt;Break Out Command Object&lt;/em&gt;. To make a long story short, this refactoring technique gets you to move a long function to a new class. Objects created using that new class are called command objects because they are mostly built around a single function, whose request and execution is the purpose of the object. It is an object that encapsulates a request, following the command pattern in &lt;a href="https://amzn.to/3zsLypY"&gt;Design Patterns&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After you’ve used &lt;em&gt;Break Out Command Object&lt;/em&gt;, you can often write tests for the new class easier than you could for the old function. Local variables in the old function can become instance variables in the new class. Often that makes it easier to break dependencies and improve the code.&lt;/p&gt;

&lt;p&gt;Here's an example in Typescript (large parts of the class have been removed to preserve pixels):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicantInfoComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;applicantCommonModel&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ApplicantCommonEditModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;isSmartMoveActive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;datePickerComponents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;QueryList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CustomDatePicker&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;flashMessageService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NotifyFlashMessageService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;validateDates&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="nf"&gt;validateBirthDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;tempDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;applicantCommonModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DateOfBirth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isSmartMoveActive&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;birthDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;datePickerComponents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_results&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;birthDate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;birthDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invalidDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flashMessageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Age must not be less than 18 years.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isSmartMoveActive&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;125&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;birthDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;datePickerComponents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_results&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;birthDate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;birthDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invalidDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flashMessageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Age must not be more than 125 years.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validateDates&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ApplicantInfoComponent&lt;/code&gt; class has a long function named &lt;code&gt;validateBirthDate&lt;/code&gt;. We can’t easily write tests for it, and it is going to be very difficult to create an instance of &lt;code&gt;ApplicantInfoComponent&lt;/code&gt; in a test harness. Let’s use &lt;em&gt;Break Out Command Object&lt;/em&gt; to move &lt;code&gt;validateBirthDate&lt;/code&gt; to a new class.&lt;/p&gt;

&lt;p&gt;The first step is to create a new class that will do the birth date validation work. We can call it &lt;code&gt;BirthDateValidator&lt;/code&gt;. After we’ve created it, we give it a constructor. The arguments of the constructor should be a reference to the original class, and the argument to the original function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BirthDateValidator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicantInfoComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might be looking at this and saying, “Wait a minute, it looks like we are going to end up in the same place. We are accepting a reference to a &lt;code&gt;ApplicantInfoComponent&lt;/code&gt;, and we already decided that we don't want to instantiate one of those in our test harness. What's the point of all this?” Wait, we are going to make things better.&lt;/p&gt;

&lt;p&gt;After we’ve made the constructor, we can add another function to the class, a function that will do the work that was done in the &lt;code&gt;validateBirthDate()&lt;/code&gt; function. We can call it &lt;code&gt;validate()&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BirthDateValidator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicantInfoComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we add the body of the &lt;code&gt;validateBirthDate()&lt;/code&gt; function to &lt;code&gt;BirthDateValidator&lt;/code&gt;. We copy the body of the old &lt;code&gt;validateBirthDate()&lt;/code&gt; function into the new &lt;code&gt;validate()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BirthDateValidator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicantInfoComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;tempDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;applicantCommonModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DateOfBirth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isSmartMoveActive&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;birthDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;datePickerComponents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_results&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;birthDate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;birthDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invalidDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flashMessageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Age must not be less than 18 years.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isSmartMoveActive&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;125&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;birthDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;datePickerComponents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_results&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;birthDate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;birthDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invalidDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flashMessageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Age must not be more than 125 years.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validateDates&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the &lt;code&gt;validate()&lt;/code&gt; on &lt;code&gt;BirthDateValidator&lt;/code&gt; has any references to instance variables or functions from &lt;code&gt;ApplicantInfoComponent&lt;/code&gt;, our compile will fail. To make it succeed, we can make getters for the variables and make the functions that it depends on public. In this case, we depend on a few variables and one &lt;code&gt;validateDates()&lt;/code&gt; function, all of which are public except for the &lt;code&gt;flashMessageService&lt;/code&gt; variable. After we make it public on &lt;code&gt;ApplicantInfoComponent&lt;/code&gt;, we can access it from a reference to the &lt;code&gt;BirthDateValidator&lt;/code&gt; class and the code compiles.&lt;/p&gt;

&lt;p&gt;Now we can make &lt;code&gt;ApplicantInfoComponent&lt;/code&gt;’s &lt;code&gt;validateBirthDate&lt;/code&gt; function delegate to the new &lt;code&gt;BirthDateValidator&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicantInfoComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="nf"&gt;validateBirthDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;birthDateValidator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BirthDateValidator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;birthDateValidator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now back to the &lt;code&gt;ApplicantInfoComponent&lt;/code&gt; dependency. The whole reason why we decided to create a new class is that &lt;code&gt;ApplicantInfoComponent&lt;/code&gt; would be too hard to instantiate in a test harness. As of right now, we still have that problem because our new &lt;code&gt;BirthDateValidator&lt;/code&gt; class still depends on a reference to &lt;code&gt;ApplicantInfoComponent&lt;/code&gt;. What we can do is extract a new interface to break the dependency on &lt;code&gt;ApplicantInfoComponent&lt;/code&gt; completely. To do that we create a new interface,  we'll call it &lt;code&gt;DateValidator&lt;/code&gt;. Then we change the reference that the &lt;code&gt;BirthDateValidator&lt;/code&gt; holds from &lt;code&gt;ApplicantInfoComponent&lt;/code&gt; to &lt;code&gt;DateValidator&lt;/code&gt;, compile, and let the compiler tell us what functions and properties have to be on the interface. Here is what the code looks like at the end:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;DateValidator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;applicantCommonModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ApplicantCommonEditModel&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;isSmartMoveActive&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;datePickerComponents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;QueryList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;CustomDatePicker&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;flashMessageService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NotifyFlashMessageService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nf"&gt;validateDates&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ApplicantInfoComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="nf"&gt;validateBirthDate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;birthDateValidator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BirthDateValidator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;birthDateValidator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BirthDateValidator&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DateValidator&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;tempDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;applicantCommonModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DateOfBirth&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isSmartMoveActive&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;birthDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;datePickerComponents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_results&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;birthDate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;birthDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invalidDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flashMessageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Age must not be less than 18 years.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isSmartMoveActive&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getFullYear&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;125&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getMonth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nx"&gt;tempDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDay&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;birthDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;datePickerComponents&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_results&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;birthDate&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="nx"&gt;birthDate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invalidDate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;flashMessageService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;warning&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Age must not be more than 125 years.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;finalValidation&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;validateDates&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;isValid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that we've extracted the code that we need to modify to a new class, we're ready to write some tests, refactor and make whatever changes we came here to make. You can see me work with &lt;em&gt;Break Out Command Object&lt;/em&gt;, and the following steps of writing tests and refactoring code, &lt;a href="https://www.youtube.com/watch?v=QIGzlJimfVI"&gt;this video series I made on working with legacy code&lt;/a&gt;.  &lt;/p&gt;

&lt;p&gt;Suggested reading:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3t7y7Jv"&gt;Refactoring: Improving the Design of Existing Code, by Martin Fowler&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/3tel2hK"&gt;Working Effectively with Legacy Code, by Michael Feathers&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>refactoring</category>
      <category>legacycode</category>
    </item>
    <item>
      <title>How to wrap an Angular directive library?</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Tue, 30 Mar 2021 01:39:51 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/how-to-wrap-an-angular-directive-library-2eil</link>
      <guid>https://forem.com/snowfrogdev/how-to-wrap-an-angular-directive-library-2eil</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rb0ZgPq---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/pablo--32-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rb0ZgPq---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/pablo--32-.png" alt="How to wrap an Angular directive library?" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You've been asked to implement a new feature in the Angular application at work. As you sit at your desk and reach for the keyboard a thought pops into your mind: "I can't be the first one to have to implement something like this. I bet there's a library that does what I need".&lt;/p&gt;

&lt;p&gt;Good for you. That's a good reflex to have in today's open-source world. Why reinvent the wheel when you can just borrow someone else's wheel? Chances are you are right; someone did have to solve the same problem you are trying to solve and was nice enough to share it with the world.&lt;/p&gt;

&lt;p&gt;So a quick search on &lt;a href="https://www.npmjs.com/"&gt;npmjs.com&lt;/a&gt; and you find exactly what you are looking for. The perfect Angular library which, through a few exported directives, does pretty much what you want.&lt;/p&gt;

&lt;p&gt;Now, you realize that it might not be the best idea to start using those directives all over the app and would like to wrap that library so that your app doesn't become tightly coupled to it. But how?&lt;/p&gt;

&lt;p&gt;When we are talking about wrapping a 3rd party library, we are usually talking about using composition to provide a new interface to our application, interface that will delegate work to the 3rd party library. That way, the 3rd party library does all the heavy lifting, but our app doesn't even know it exists, it just knows about the pretty wrapper we've made for it.&lt;/p&gt;

&lt;p&gt;If you are familiar with design patterns, you'll probably end up using something that looks a lot like the &lt;a href="https://refactoring.guru/design-patterns/adapter"&gt;Adapter&lt;/a&gt;, the &lt;a href="https://refactoring.guru/design-patterns/proxy"&gt;Proxy&lt;/a&gt;,  or the &lt;a href="https://refactoring.guru/design-patterns/facade"&gt;Façade&lt;/a&gt; pattern.&lt;/p&gt;

&lt;p&gt;For our demonstration, we'll wrap the &lt;a href="https://github.com/mattlewis92/angular-resizable-element"&gt;angular-resizable-element&lt;/a&gt; library. You can try it out, and see the code associated with this article, in the following &lt;a href="https://stackblitz.com/edit/wrapping-angular-directive?file=src/app/app.component.html"&gt;Stackblitz&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/wrapping-angular-directive?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h1 id="choose-your-api"&gt;Choose your API&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://github.com/mattlewis92/angular-resizable-element"&gt;angular-resizable-element&lt;/a&gt; is a cool little library that makes it possible to resize elements by dragging their edges. Let's take a quick look at how it works. According to its &lt;a href="https://mattlewis92.github.io/angular-resizable-element/docs/modules/ResizableModule.html"&gt;documentation&lt;/a&gt;, it provides two directives through it's exported module: &lt;code&gt;&lt;a href="https://mattlewis92.github.io/angular-resizable-element/docs/directives/ResizableDirective.html"&gt;ResizableDirective&lt;/a&gt;&lt;/code&gt; and &lt;code&gt;&lt;a href="https://mattlewis92.github.io/angular-resizable-element/docs/directives/ResizeHandleDirective.html"&gt;ResizeHandleDirective&lt;/a&gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Upon examination, we conclude that we don't really need to use &lt;code&gt;ResizeHandleDirective&lt;/code&gt;. It's purpose is to give finer grain control over each handle to the sides of the resizable element and we don't really care about that. So that leaves us with &lt;code&gt;ResizableDirective&lt;/code&gt;. Looking at the docs, we see that it takes in 9 inputs and emits 3 outputs.&lt;/p&gt;

&lt;p&gt;As is often the case with libraries, they tend to offer a much wider API than you actually need. Do not feel like you have to mirror the 3rd party library with your wrapper. In fact, your wrapper's API should only provide what your app needs. No more, no less.&lt;/p&gt;

&lt;p&gt;In our case, after a careful examination of our requirements, we determine that we don't need to provide the equivalent of the &lt;code&gt;allowNegativeResizes&lt;/code&gt;, &lt;code&gt;mouseMoveThrottleMS&lt;/code&gt;, &lt;code&gt;resizeCursors&lt;/code&gt;, &lt;code&gt;resizeCursorPrecision&lt;/code&gt; and  &lt;code&gt;resizeSnapGrid&lt;/code&gt; inputs. Other than that, it would make sense for our wrapper to provide a similar interface to that of the 3rd party library, as it will cover our needs nicely.&lt;/p&gt;

&lt;h1 id="wrap-it-up"&gt;Wrap it up&lt;/h1&gt;

&lt;p&gt;At the moment, our demo component uses the 3rd party library directly and the code looks like this:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Drag and pull the edges of the rectangle&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"rectangle"&lt;/span&gt;
    &lt;span class="na"&gt;[ngStyle]=&lt;/span&gt;&lt;span class="s"&gt;"style"&lt;/span&gt;
    &lt;span class="na"&gt;mwlResizable&lt;/span&gt;
    &lt;span class="na"&gt;[validateResize]=&lt;/span&gt;&lt;span class="s"&gt;"validate"&lt;/span&gt;
    &lt;span class="na"&gt;[enableGhostResize]=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
    &lt;span class="na"&gt;(resizeEnd)=&lt;/span&gt;&lt;span class="s"&gt;"onResizeEnd($event)"&lt;/span&gt;
    &lt;span class="na"&gt;[resizeEdges]=&lt;/span&gt;&lt;span class="s"&gt;"{bottom: true, right: true, top: true, left: true}"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ResizeEvent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;angular-resizable-element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-app&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;templateUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./app.component.html&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;styleUrls&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./app.component.css&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;

  &lt;span class="nf"&gt;validate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ResizeEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;MIN_DIMENSIONS_PX&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;amp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;amp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;amp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;amp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;MIN_DIMENSIONS_PX&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
        &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;MIN_DIMENSIONS_PX&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;onResizeEnd&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ResizeEvent&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fixed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;left&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;top&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rectangle&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;height&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;px`&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, we are using the &lt;code&gt;mwlResizable&lt;/code&gt; directive selector from the library in our template and its &lt;code&gt;ResizeEvent&lt;/code&gt; interface in the component. We need to use our wrapper instead. So let's do that.&lt;/p&gt;

&lt;h2 id="step-one-inputs-and-outputs"&gt;Step one: inputs and outputs&lt;/h2&gt;

&lt;p&gt;As a first step I often find it useful to define the inputs and outputs of our wrapper. To begin we will create a new directive in a new file for our wrapper. Since we plan on providing a similar, yet simpler, interface than the one exposed by the library, we can use its &lt;a href="https://github.com/mattlewis92/angular-resizable-element/blob/master/src/resizable.directive.ts"&gt;source code&lt;/a&gt; as a base and simply copy the inputs and outputs that we plan to provide. After this step we end up with something like this:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[resizableWrapper]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ResizableDirective&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnChanges&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;validateResize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resizeEvent&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ResizeEvent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;resizeEdges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Edges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{};&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;enableGhostResize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;ghostElementPositioning&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fixed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;absolute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;fixed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;resizeStart&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;ResizeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;();&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;resizing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;ResizeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;();&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Output&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;resizeEnd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;EventEmitter&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;lt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="nx"&gt;ResizeEvent&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll also want to make sure that you don't just reuse the library's interfaces and instead provide your own. For instance, in the above code we have the &lt;code&gt;ResizeEvent&lt;/code&gt; and &lt;code&gt;Edges&lt;/code&gt; interfaces. We made sure to define our own, in separate files.&lt;/p&gt;

&lt;h2 id="step-two-constructor-parameters"&gt;Step two: constructor parameters&lt;/h2&gt;

&lt;p&gt;As we will be creating an instance of the library's directive whenever we create an instance of our wrapper, we will need to pass the appropriate dependencies. Here the 3rd party directive's constructor:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;PLATFORM_ID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;platformId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Renderer2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;elm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NgZone&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pointerEventListeners&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;PointerEventListeners&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;zone&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So we'll need to pass in four dependencies. All four are part of the &lt;code&gt;@angular/core&lt;/code&gt; package and therefore should be easy for the DI system to resolve. Let's do that now.&lt;/p&gt;

&lt;p&gt;This step is not particularly hard. All we need to do is add the library's directive to our wrapper's constructor and supply Angular's DI with a factory provider.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;resizableDirectiveFactory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;platformId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Renderer2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;elm&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NgZone&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ResizableDirective&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;platformId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;elm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;zone&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resizableDirectiveProvider&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ResizableDirective&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;useFactory&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;resizableDirectiveFactory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;deps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;PLATFORM_ID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Renderer2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ElementRef&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;NgZone&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[resizableWrapper]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;resizableDirectiveProvider&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ResizableWrapperDirective&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnChanges&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ResizableDirective&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2 id="step-three-lifecycle-hooks"&gt;Step three: Lifecycle hooks&lt;/h2&gt;

&lt;p&gt;One thing to keep in mind when wrapping a directive in Angular is that we need to account for the lifecycle hooks. They can be viewed as part of your wrapper's API. You'll probably want to have the same lifecycle hooks as the directive you are wrapping. Keeping that in mind, let's look at the three hooks we'll need to implement. &lt;br&gt;&lt;br&gt;First &lt;code&gt;ngOnInit&lt;/code&gt;. The first thing we wanna do is hook up the outputs.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resizeStart&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resizeStart&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resizing&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resizing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resizeEnd&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;gt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resizeEnd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;emit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep in mind that this example is very simple because our event interfaces are a mirror image of the library's interfaces. Were it not the case, you would have to map them to your own interfaces before emitting them.&lt;/p&gt;

&lt;p&gt;Ok, all that is left is to delegate to the library's own &lt;code&gt;ngOnInit&lt;/code&gt; function.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;

  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As simple as that. Moving on to &lt;code&gt;ngOnChanges&lt;/code&gt; which gets called before &lt;code&gt;ngOnInit&lt;/code&gt; and every time one or more data-bound input properties change. So guess what we need to do in that function. That's right, assign our input properties... and delegate to the library's &lt;code&gt;ngOnChanges&lt;/code&gt; function.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;ngOnChanges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SimpleChanges&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validateResize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validateResize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validateResize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resizeEdges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resizeEdges&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;resizeEdges&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enableGhostResize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enableGhostResize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;enableGhostResize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ghostElementPositioning&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ghostElementPositioning&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ghostElementPositioning&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ngOnChanges&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;changes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And finally, &lt;code&gt;ngOnDestroy&lt;/code&gt;&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;library&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2 id="step-four-declare-your-wrapper-and-use-it"&gt;Step four: Declare your wrapper and use it&lt;/h2&gt;

&lt;p&gt;All that is left is to add our wrapper to our module and to use it in our template.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NgModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;BrowserModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular/platform-browser&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;FormsModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular/forms&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./app.component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ResizableWrapperDirective&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../lib/resizable-wrapper.directive&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;BrowserModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;FormsModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ResizableWrapperDirective&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;bootstrap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppComponent&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, our module has no references to the 3rd party &lt;a href="https://github.com/mattlewis92/angular-resizable-element"&gt;angular-resizable-element&lt;/a&gt; library. It only declares our wrapper directive. Our template and component also now only depend on our wrapper directive.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"text-center"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Drag and pull the edges of the rectangle&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt;
    &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"rectangle"&lt;/span&gt;
    &lt;span class="na"&gt;[ngStyle]=&lt;/span&gt;&lt;span class="s"&gt;"style"&lt;/span&gt;
    &lt;span class="na"&gt;resizableWrapper&lt;/span&gt;
    &lt;span class="na"&gt;[validateResize]=&lt;/span&gt;&lt;span class="s"&gt;"validate"&lt;/span&gt;
    &lt;span class="na"&gt;[enableGhostResize]=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;
    &lt;span class="na"&gt;(resizeEnd)=&lt;/span&gt;&lt;span class="s"&gt;"onResizeEnd($event)"&lt;/span&gt;
    &lt;span class="na"&gt;[resizeEdges]=&lt;/span&gt;&lt;span class="s"&gt;"{bottom: true, right: true, top: true, left: true}"&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1 id="conclusion"&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;Wrapping 3rd party libraries is generally good practice but it can be a challenge to do so when dealing with Angular directives. Each library is different and will require a slightly different approach but the four steps laid out in this article should serve as a good foundation.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>dependencyinjection</category>
    </item>
    <item>
      <title>WSL is a memory hog, deal with it</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Thu, 11 Mar 2021 18:17:15 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/wsl-is-a-memory-hog-deal-with-it-14ja</link>
      <guid>https://forem.com/snowfrogdev/wsl-is-a-memory-hog-deal-with-it-14ja</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MeC2-GtO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/pablo--31-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MeC2-GtO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/pablo--31-.png" alt="WSL is a memory hog, deal with it" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently upgraded my computer's RAM to 32GB from 16GB. It was running fine but ever since I started doing more work with Docker containers, it felt like it would get sluggish once in awhile.  &lt;/p&gt;

&lt;p&gt;With now double the RAM, I figured I'd be golden. It turns out it isn't that simple. This week, the company I work for decided to start using containers for most of our project's dependencies, you know, SQL server, Solr, Redis etc... There is quite a few of them, but I've never had a problem running them simultaneously on my machine.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;docker-compose up&lt;/code&gt; later and my computer became sluggish again. What?! A quick look at the &lt;code&gt;Processes&lt;/code&gt; tab in &lt;code&gt;Task Manager&lt;/code&gt; showed that 98% of my system's memory was being used and 23GB out of my 32GB was being used by something called Vmmem. What the heck is Vmmem and why is it using so much memory?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NOI2nLTl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NOI2nLTl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-1.png" alt="WSL is a memory hog, deal with it" width="800" height="448"&gt;&lt;/a&gt;Damn you Vmmem!&lt;/p&gt;

&lt;p&gt;A quick Google search later produced some answers. The short of it, Vmmem is the process that runs the Windows Subsystem for Linux (WSL), which is used by Docker on Windows. So Vmmem = WSL = Docker. This is a major over-simplification but if you never use WSL directly and are only using it for Docker, for you it's pretty close to reality.  &lt;/p&gt;

&lt;p&gt;Anyway, even though I now understood what this Vmmem thing was, it was pretty clear in my mind that there was no way the roughly 30 processes I was running inside Docker containers needed to consume this much memory. Most of them were relatively lightweight.  &lt;/p&gt;

&lt;p&gt;The first thing I started by doing was to bring down all my containers to see if this would help. After &lt;code&gt;docker-compose down&lt;/code&gt; the situation improved. But not nearly as much as it should have.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VbXl5kqK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VbXl5kqK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-2.png" alt="WSL is a memory hog, deal with it" width="800" height="446"&gt;&lt;/a&gt;Better, but not nearly enough&lt;/p&gt;

&lt;p&gt;Why in the world is Vmmem still using 17 GB of RAM if I'm no longer running any Docker containers? Well, let's find out, shall we? In the terminal, I switched over to WSL and ran the Linux &lt;code&gt;free&lt;/code&gt; command which gives you an overview of memory usage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6WbZ99zq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6WbZ99zq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-3.png" alt="WSL is a memory hog, deal with it" width="800" height="136"&gt;&lt;/a&gt;Ah Ah! WSL you memory thief you!&lt;/p&gt;

&lt;p&gt;As far as WSL was concerned, it considered that it had rights over 25GB of my system's memory. At the moment is was using 8.8 GB (for what?!) but what is interesting is that it had reserved a full 14 GB as buff/cache.&lt;/p&gt;

&lt;p&gt;You see, nature, and Linux apparently, abhors a vacuum. Since it considered that it had rights over 25 GB or my RAM but it didn't need all of it, it figured it would just earmark whatever it didn't need as cache. You know, because why not. It's not like the host machine has any need for memory on the Windows side of things (looking at you Google Chrome).  &lt;/p&gt;

&lt;p&gt;So why does WSL feel entitled to this much RAM. Well, it turns out that, depending on which build of Windows or WSL you are on, WSL gets access to 50%-80% of your system's RAM by default. Again, what?! 25 GB of RAM is way more than is needed to run a few fistfuls of Docker containers.  &lt;/p&gt;

&lt;p&gt;Thankfully, there is a way to fix this. To impose our will on WSL and get it to forget about that silly default setting, all we need to do is place a &lt;code&gt;.wslconfig&lt;/code&gt; file into the root directory of our users folder: &lt;code&gt;C:\Users\&amp;lt;yourUserName&amp;gt;\.wslconfig&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my case I ended up limiting WSL to 8 GB of my RAM and, while I was at it, 4 of my 8 CPU cores - it has access to all of them by default.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--b6rzzo99--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b6rzzo99--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-5.png" alt="WSL is a memory hog, deal with it" width="777" height="228"&gt;&lt;/a&gt;.wslconfig, the hero of this story&lt;/p&gt;

&lt;p&gt;All that was left to do was stop and restart WSL. A simple &lt;code&gt;wsl --shutdown&lt;/code&gt; in the terminal will stop WSL. At that point Docker will notice that it has shutdown and offer to restart it. Let it do that for you.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--bfaSGacL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--bfaSGacL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-6.png" alt="WSL is a memory hog, deal with it" width="365" height="201"&gt;&lt;/a&gt;Docker offers to restart WSL&lt;/p&gt;

&lt;p&gt;And there you have it. We have tamed the hungry beast.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wXZsCXLz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wXZsCXLz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-9.png" alt="WSL is a memory hog, deal with it" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--X0w13UQm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--X0w13UQm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/03/image-10.png" alt="WSL is a memory hog, deal with it" width="800" height="135"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are other setting options you can set for the Windows Subsystem for Linux in that &lt;code&gt;.wsconfig&lt;/code&gt; file, you can find them &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/wsl-config#configure-global-options-with-wslconfig"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>wsl</category>
      <category>hardware</category>
      <category>memory</category>
      <category>windows</category>
    </item>
    <item>
      <title>Are Single-Page Applications Bounded Contexts - and who the heck cares?</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Thu, 18 Feb 2021 01:35:40 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/are-single-page-applications-bounded-contexts-and-who-the-heck-cares-5d2k</link>
      <guid>https://forem.com/snowfrogdev/are-single-page-applications-bounded-contexts-and-who-the-heck-cares-5d2k</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cmSE7xJG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/pablo--22-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cmSE7xJG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/pablo--22-.png" alt="Are Single-Page Applications Bounded Contexts - and who the heck cares?" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://blog.snowfrog.dev/single-page-applications-are-not-bounded-contexts-what"&gt;first&lt;/a&gt; and &lt;a href="https://blog.snowfrog.dev/are-single-page-applications-bounded-contexts-inside"&gt;second&lt;/a&gt; article in the series we have established that a Bounded Context includes more than just the domain model but extends to the other layers of our system, in a vertical slice.  &lt;/p&gt;

&lt;p&gt;To better  understand how this all plays out, and why this means that a Single-Page Application should be part of it's server-side API, I decided to map out a simple class diagram over &lt;a href="http://cleancoder.com/"&gt;Uncle Bob&lt;/a&gt;'s famous clean architecture. First, for comparison, I mapped out the typical MVC application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iI-GXw1u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/image-5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iI-GXw1u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/image-5.png" alt="Are Single-Page Applications Bounded Contexts - and who the heck cares?" width="800" height="778"&gt;&lt;/a&gt;Typical MVC Application&lt;/p&gt;

&lt;p&gt;If you are not familiar with this architecture or diagram you'll find plenty of examples with a quick Google search for "Clean Architecture". Suffice to say that at the center, in yellow, is the domain model. This diagram is meant to represent one specific use case, a vertical slice, dealing with Products. According to &lt;a href="https://vaughnvernon.com/"&gt;Vernon&lt;/a&gt;, this entire diagram could constitute a Bounded Context.  &lt;/p&gt;

&lt;p&gt;Now let's look at what the same use case would look like with a SPA.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8rYQhTjL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/image-6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8rYQhTjL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/image-6.png" alt="Are Single-Page Applications Bounded Contexts - and who the heck cares?" width="800" height="774"&gt;&lt;/a&gt;API Endpoint Server with SPA client&lt;/p&gt;

&lt;p&gt;There is a bit more going on here, as can be expected. But as you can see, the core of our application didn't change. We are still using the same domain model, application service and repository interface. The only thing that changed is that we have added a few intermediaries between our &lt;code&gt;ProductController&lt;/code&gt; and our &lt;code&gt;View&lt;/code&gt;. That's normal since we now have to go through the &lt;code&gt;Web&lt;/code&gt; to reach it. The important thing here is to realize that the fact that we have swapped our client from a traditional server side MVC UI to a SPA didn't change anything for the core domain. And everything in this diagram is is still a vertical slice, handling the same use-case, dealing with Products.  &lt;/p&gt;

&lt;p&gt;So, if the setup in the first diagram is a Bounded Context it stands to reason that the setup in the second diagram also represents one Bounded Context. We haven't changed the domain model. We haven't changed the words we use to refer to the components in the domain model. We are still talking the same Ubiquitous Language.  &lt;/p&gt;

&lt;p&gt;As stated previously, the components in the green and blue layers are not part of the domain model, but they ARE part of the Bounded Context. If we swap components in and out of the green and blue layers but don't add anything to the pink and yellow ones, we're still dealing with the same domain model, the same Ubiquitous Language... the same Bounded Context.&lt;/p&gt;

&lt;h1&gt;
  
  
  Does it even matter?
&lt;/h1&gt;

&lt;p&gt;When I was discussing this with &lt;a href="https://ardalis.com/"&gt;Steve&lt;/a&gt; - remember him from the first article? - he rightfully reminded me that "all models are wrong, but some are useful". So the question is, despite the fact that, according to our analysis of the DDD literature, viewing the SPA as part of the same BC as the server-side API is more "right" than viewing it as a separate BC, is it more useful?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;All models are wrong, but some are useful&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I honestly don't know for sure, but I do see some advantages to modelling it that way. One of them stems from what Vernon says about Bounded Contexts and teams. He says: "There should be one team assigned to work on one Bounded Context. [...] It is especially important to be clear that one team works on a single Bounded Context."   &lt;/p&gt;

&lt;p&gt;I do believe that the best way to develop software is generally to work in small, multidisciplinary teams, using &lt;a href="https://deviq.com/practices/vertical-slices"&gt;vertical slices&lt;/a&gt;. Given what Vernon says, if we were to model the SPA as it's own BC, we would presumably have different teams working on the SPA and the back-end, which I think is less than ideal. But that's a topic for another blog post.  &lt;/p&gt;

&lt;p&gt;What do you think? Is it more useful to view the SPA as its own BC, or as part of the server-side API's BC? Why? Let me know in the comments.&lt;/p&gt;

</description>
      <category>singlepageapplication</category>
      <category>domaindrivendesign</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Are Single-Page Applications Bounded Contexts - and what the heck is inside a Bounded Context?</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Thu, 18 Feb 2021 01:35:28 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/are-single-page-applications-bounded-contexts-and-what-the-heck-is-inside-a-bounded-context-2mmp</link>
      <guid>https://forem.com/snowfrogdev/are-single-page-applications-bounded-contexts-and-what-the-heck-is-inside-a-bounded-context-2mmp</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Uqxsq2-5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/pablo--21-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Uqxsq2-5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/pablo--21-.png" alt="Are Single-Page Applications Bounded Contexts - and what the heck is inside a Bounded Context?" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://blog.snowfrog.dev/single-page-applications-are-not-bounded-contexts-what"&gt;previous&lt;/a&gt; article in this series we arrived at a simple, but rather abstract definition of what a Bounded Context(BC) is. This definition seemed to confirm my intuition that a Single-Page Application(SPA) should be part of the same BC as its server-side API, but does it really?&lt;/p&gt;

&lt;p&gt;To my mind, if in the SPA I'm dealing with a &lt;code&gt;ProductComponent&lt;/code&gt;, &lt;code&gt;ProductView&lt;/code&gt; or &lt;code&gt;ProductViewModel&lt;/code&gt;, the data for which I received from the &lt;code&gt;api/product/:id&lt;/code&gt; endpoint, endpoint that was custom made for the particular use case served by &lt;code&gt;ProductComponent&lt;/code&gt; by members of my team, then we're talking the same Ubiquitous Language.&lt;/p&gt;

&lt;p&gt;I'll admit that due to the abstract nature of the definition of a Bounded Context, someone could arrive at a different conclusion. My conclusion is influenced by the fact that I'm a full-stack developper and usually work on multi-disciplined teams who do &lt;a href="https://deviq.com/practices/vertical-slices"&gt;vertical slices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But what if the people in charge of developing the &lt;code&gt;api/product/:id&lt;/code&gt; endpoint are technically not on my team and teams are split between client-side and server-side 🤮? Also, the &lt;code&gt;ProductViewModel&lt;/code&gt; might not be a perfect 1 to 1 mapping of the server-side &lt;code&gt;Product&lt;/code&gt; entity, doesn't that mean that when I'm thinking of a Product I'm not thinking of exactly the same thing as my server-side brethren?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Bounded Context is composed of more than a domain model.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By that logic though, even in a standard MVC type app, where the pages are rendered on the server, you would have to say that the Bounded Context excludes the Controller, the View and the Model. Is that what &lt;a href="https://vaughnvernon.com/"&gt;Vernon&lt;/a&gt; envisions when he sees a BC? Does a BC only contain the classes and interfaces that are part of the domain model (entities, value object, domain services, domain events and repositories) or does it extend to the classes (application services, controllers, etc.) in other layers?&lt;/p&gt;

&lt;p&gt;To those questions, at least, Vernon offers precise and satisfying answers, with an accompanying diagram no less. He says that "There is another question that you may have wondered about. What’s inside a Bounded Context? Using this Ports and Adapters architecture diagram, you can see that a Bounded Context is composed of more than a domain model.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vHCKJYHq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vHCKJYHq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/image.png" alt="Are Single-Page Applications Bounded Contexts - and what the heck is inside a Bounded Context?" width="696" height="256"&gt;&lt;/a&gt;Domain-Driven Design Distilled - Vaughn Vernon&lt;/p&gt;

&lt;p&gt;These layers are common in a Bounded Context: Input Adapters, such as user interface controllers, REST endpoints, and message listeners; Application Services that orchestrate use cases and manage transactions; the domain model that we’ve been focusing on; and Output Adapters such as persistence management and message senders."&lt;/p&gt;

&lt;p&gt;So there we have it. When talking about Bounded Contexts, Vernon, at least, is talking about the entire stack. A bit like a vertical slice or slices.&lt;/p&gt;

&lt;p&gt;But surely Vernon didn't have SPAs in mind when he said this? SPAs are different, they are more than just UI, some even have a bit of business and application logic. Plus, they are separate applications (it's in the name after all), that run on a different machine, surely BCs do not cross process boundaries?&lt;/p&gt;

&lt;p&gt;To this I answer, really? Why not? Where in the definitions of a Bounded Context or the Ubiquitous Language do we see any mention of anything that has to do, even remotely, with the concept of deployment location or process boundaries? Nowhere, that's where.&lt;/p&gt;

&lt;p&gt;To add some weight to the argument that it is absolutely not antithesis to DDD for a Bounded Context to span multiple deployment artifacts or processes, here's what Vernon says in 'Implementing DDD': "A Bounded Context does not dictate the creation of a single kind of project artifact. It’s not an individual component, document, or diagram. So it’s not a JAR or DLL, but these can be used to deploy a Bounded Context as described later in the chapter."&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Bounded Context does not dictate the creation of a single kind of project artifact. It’s not an individual component, document, or diagram.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So a BC does not equal a package, project or any other kind of deployment artifact. It can, but it doesn't have to. For example, a DLL could contain more than one BC and one BC could span several DLLs.  &lt;/p&gt;

&lt;p&gt;Regarding the idea that a BC can also span several processes and physical or virtual machines Vernon gives the following explanation while talking about an example application that deals with Scrum-based software project management: "some consider a microservice to be much smaller than a DDD Bounded Context. Using that definition, a microservice models only one concept and manages one narrow type of data. An example of such a microservice is a Product and another is a BacklogItem. If this is the granularity that you consider a worthy microservice, understand that both the Product microservice and the BacklogItem microservice will still be in the same larger, logical Bounded Context. The two small microservice components have only different deployment units, which may also have an impact on how they interact. Linguistically they are still within the same Scrum-based contextual and semantic boundary."&lt;/p&gt;

&lt;p&gt;Yes he is talking about microservices, but the same principles apply when talking about a SPA. The fact that it runs in a different process and is deployed separately is not a valid reason not to consider the SPA as part of the same BC as the rest of the server-side BC. These factors are orthogonal to the concept of a BC.&lt;/p&gt;

&lt;p&gt;Keep reading, in the &lt;a href="https://blog.snowfrog.dev/are-single-page-applications-bounded-contexts-who-cares"&gt;next&lt;/a&gt; article we will illustrate our findings using Uncle Bob's famous Clean Architecture and discuss WHY it is preferable to view the SPA as part of its server-side API's Bounded Context.&lt;/p&gt;

</description>
      <category>singlepageapplication</category>
      <category>domaindrivendesign</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Are Single-Page Applications Bounded Contexts - and what the heck is a Bounded Context?</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Thu, 18 Feb 2021 01:35:13 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/are-single-page-applications-bounded-contexts-and-what-the-heck-is-a-bounded-context-375j</link>
      <guid>https://forem.com/snowfrogdev/are-single-page-applications-bounded-contexts-and-what-the-heck-is-a-bounded-context-375j</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kh_bfNYJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/pablo--20-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kh_bfNYJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2021/02/pablo--20-.png" alt="Are Single-Page Applications Bounded Contexts - and what the heck is a Bounded Context?" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That is the question I have been pondering these past few weeks. It led to a series of interesting conversations with &lt;a href="https://ardalis.com/"&gt;Steve "ardalis" Smith&lt;/a&gt; on our &lt;a href="https://devbetter.com/"&gt;devBetter&lt;/a&gt; community Discord server. At the time of these discussions I wasn't sure of the answer. I was however leaning towards the idea that most Single-Page Applications (SPA) were not Bounded Contexts (BC) but in fact belonged to the BC of their corresponding server-side API.&lt;/p&gt;

&lt;p&gt;Steve had the good idea to consult the Twittersphere to see what other developers thought. The results were far from conclusive with only 54% of respondents being of the opinion that the SPA was part of its server-side API's Bounded Context. A majority, but barely.&lt;/p&gt;


&lt;blockquote&gt;
&lt;p&gt;Folks building SPAs with &lt;a href="https://twitter.com/hashtag/DDDesign?src=hash&amp;amp;ref_src=twsrc%5Etfw"&gt;#DDDesign&lt;/a&gt; and considering Bounded Contexts (BCs). Are the SPA and its server-side APIs it uses (see poll):&lt;br&gt;&lt;br&gt;RT for reach pls.&lt;/p&gt;— Steve "ardalis" Smith (&lt;a class="mentioned-user" href="https://dev.to/ardalis"&gt;@ardalis&lt;/a&gt;) &lt;a href="https://twitter.com/ardalis/status/1356367598976380928?ref_src=twsrc%5Etfw"&gt;February 1, 2021&lt;/a&gt;
&lt;/blockquote&gt; 

&lt;p&gt;I would need to analyze this question further to come to a satisfying conclusion. So I decided to go back to the source, to the authoritative works on the subject of Domain Driven Design (DDD), namely, the works of &lt;a href="https://www.domainlanguage.com/"&gt;Eric Evans&lt;/a&gt; and &lt;a href="https://vaughnvernon.com/"&gt;Vaughn Vernon&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This analysis led me to the conclusion that the majority of SPAs (those backed by a corresponding, in-house, server-side API) are not BCs in their own right but, rather, belong to the BC of their server-side API. Here's why.&lt;/p&gt;

&lt;h1&gt;
  
  
  First, some definitions
&lt;/h1&gt;

&lt;p&gt;Our question involves three elements: 1) a Single-Page Application 2) a server-side API 3) the concept of a Bounded Context. I thought it would be prudent to make sure I was really clear on what those three things were before trying to answer our question.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single-Page application&lt;/strong&gt; : A client-side web application that doesn't need to load new pages from the server. The kind of application you would generally write with Angular, React, Vue.js or Blazor frameworks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server-side API&lt;/strong&gt; : A server-side application containing business logic and exposing an API to web clients, often through REST endpoints. You could write such an application with the ASP.Net or the Spring frameworks, to name but a few. These applications are usually backed by a database.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bounded Context&lt;/strong&gt; : .... and this is were we get in trouble. As I read through the DDD body of work, I quickly realized that the concept of a Bounded Context was not that easy to define. This is precisely why it seemed hard to find a clear cut answer to our question. So, before we can go any further, a discussion on what constitutes a Bounded Context is in order.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Bounded Context
&lt;/h2&gt;

&lt;p&gt;In Evans' blue book on DDD, in the glossary, we find the following definition for Bounded Context: "The delimited applicability of a particular model. BOUNDING CONTEXTS gives team members a clear and shared understanding of what has to be consistent and what can develop independently." A little vague, I know.&lt;/p&gt;

&lt;p&gt;Vernon, for his part, says in 'DDD Distilled'  that a "&lt;em&gt;Bounded Context&lt;/em&gt; is a semantic contextual boundary. This means that within the boundary each component of the software model has specific meaning and does specific things. The components inside a &lt;em&gt;Bounded Context&lt;/em&gt; are context specific and semantically motivated. That's simple enough. " No Vaughn, no, it's not simple enough. But thanks for trying.&lt;/p&gt;

&lt;p&gt;To understand both of Evans' and Vernon's definitions, you kind of have to understand the concept of Ubiquitous Language(UL). Notice how Vernon talks about a "semantic contextual boundary" and about the components being "semantically motivated"? He's talking about the UL. In other words, according to Vernon, one BC equals one UL.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A Bounded Context is a part of the system where the same people work on the same things and call those things by the same names.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So what is a Ubiquitous Language? Evans says it is "a language structured around the domain model and used by all team members to connect all the activities of the team with the software." In other words, on the team, if I'm talking about a Product or a Customer, everyone knows exactly what I'm referring to. Now, another team working on the same app might also have to deal with Products or Customers but they have a slightly different definition of what they are and what they do. As such they do not speak our Ubiquitous Language and therefore are dealing with a different Bounded Context.&lt;/p&gt;

&lt;p&gt;So, if I had to give my own, super simple, definition of a Bounded Context I would say that it is a part of the system where the same people work on the same things and call those things by the same names.&lt;/p&gt;

&lt;p&gt;Yeah, I know, still a little vague. I wasn't very satisfied either. In this article we have defined, in the abstract, what a Bounded Context IS. Still on our quest to determine if a SPA is a Bounded Context, in the &lt;a href="https://blog.snowfrog.dev/are-single-page-applications-bounded-contexts-inside"&gt;next&lt;/a&gt; article we will look at what a Bounded Context HAS. What is part of a Bounded Context? What does it contain? &lt;a href="https://blog.snowfrog.dev/are-single-page-applications-bounded-contexts-inside"&gt;Keep reading to find out&lt;/a&gt;...&lt;/p&gt;

</description>
      <category>singlepageapplication</category>
      <category>domaindrivendesign</category>
      <category>architecture</category>
    </item>
    <item>
      <title>The Spy of Testadel: A Medieval Testing Tale</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Thu, 26 Dec 2019 16:55:57 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/the-spy-of-testadel-a-medieval-testing-tale-4062</link>
      <guid>https://forem.com/snowfrogdev/the-spy-of-testadel-a-medieval-testing-tale-4062</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HfgZUcGR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://images.unsplash.com/photo-1514539079130-25950c84af65%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HfgZUcGR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://images.unsplash.com/photo-1514539079130-25950c84af65%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="The Spy of Testadel: A Medieval Testing Tale" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The year is 1453. After 116 years of war, your kingdom, Testadel, is finally at peace. Now is the time to rebuild and strengthen your relationships with your neighbours. To the North lies the fiefdom of Lord PureFunction, who fought valiantly at your side during the war. In an effort to establish stronger commercial ties, you both sign a treaty whereby you promise to supply his keep with as many sheep as you can every month, in exchange for 15 pieces of gold per sheep.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LordPureFunctionsKeep&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;priceOfOneSheep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;calculatePaymentForSheep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sheep&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;sheep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;priceOfOneSheep&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a few months, as was agreed by both parties, an independent auditor travels to Lord PureFunction's keep to make sure that the commercial agreement is being fulfilled properly.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;LordPureFunctionsKeep&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should pay 300 gold pieces when supplied with 20 sheep&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;keep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;LordPureFunctionsKeep&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;keep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;calculatePaymentForSheep&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payment&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upon completion, the auditor reports that Lord PureFunction was very accommodating. A true paragon of virtue, PureFunction opened up its books willingly and complied happily with every request from the auditor. "Usually", the auditor says, "people try to hide things from me, but not so with Lord PureFunction. You are lucky to have such a transparent and trustworthy ally".  &lt;/p&gt;

&lt;p&gt;Happy with the auditor's findings and secure in the knowledge that you have a strong relationship with your ally to the North, you turn your attention to the South. There lie the ravaged lands of Sir SideEffects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XAItITar--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://images.unsplash.com/photo-1539871283820-aec0272ade46%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XAItITar--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://images.unsplash.com/photo-1539871283820-aec0272ade46%3Fixlib%3Drb-1.2.1%26q%3D80%26fm%3Djpg%26crop%3Dentropy%26cs%3Dtinysrgb%26w%3D1080%26fit%3Dmax%26ixid%3DeyJhcHBfaWQiOjExNzczfQ" alt="The Spy of Testadel: A Medieval Testing Tale" width="800" height="450"&gt;&lt;/a&gt;Photo by &lt;a href="https://unsplash.com/@udit_arun?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;udit saptarshi&lt;/a&gt; / &lt;a href="https://unsplash.com/?utm_source=ghost&amp;amp;utm_medium=referral&amp;amp;utm_campaign=api-credit"&gt;Unsplash&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Sir SideEffects had the misfortune of taking the other side, the losing side, during the recently ended war. The peace treaty that ended the war, and that he signed reluctantly, imposes serious limitations on the amount of weapons he is allowed to stockpile and forbids him from having any contacts with his previous allies.  &lt;/p&gt;

&lt;p&gt;It is agreed that Sir SideEffects will provide every month to your envoy a full account of his weapons stock.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SirSideEffectsCamp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Weapons&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;scribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Scribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;reportWeaponsStock&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scribe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeWeaponsReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&amp;lt;!--kg-card-end: markdown--&amp;gt;&amp;lt;!--kg-card-begin: markdown--&amp;gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SirSideEffectsCamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should report having less than 50 weapons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;camp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SirSideEffectsCamp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weaponsStock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;camp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reportWeaponsStock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weaponsStock&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeLessThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For the first few months, Sir SideEffects seems to abide by the terms of his surrender. Every month your envoy shows up at the gate, asks for a report, and every month Sir SideEffects has a piece of paper attached to a rock thrown over the rampart, detailing the level of his weapons stock. The amount varies a little every month but is always below the agreed ceiling.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--34yHw9pr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2019/12/pablo--7-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--34yHw9pr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2019/12/pablo--7-.png" alt="The Spy of Testadel: A Medieval Testing Tale" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything seems under control until one day your envoy asks to speak with you about a matter that seems to have him worried. "My lord, I fear that Sir SideEffects might be up to no good. Indeed, this is the fourth month in a row that he has reported exactly 6 weapons. Something's not right; the amount always used to vary before".&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SirSideEffectsCamp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;armoury&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Weapons&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;scribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Scribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;reportWeaponsStock&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scribe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeWeaponsReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- Now reports 6 weapons&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Taking this matter to heart, you convene a meeting of your councillors to address the situation with Sir SideEffects. After debating for the better part of the day, everyone agrees that although it is highly suspicious that the reports for the past fours months have all been the same, it is not in itself a proof of foul play. More information needs to be gathered. But how? Sir SideEffects keeps the gate to his camp closed to outsiders and it is impossible to see what is going on inside.&lt;/p&gt;

&lt;p&gt;One of your councillors speaks up. "Sir, we need to send a spy. Someone crafty enough to find a way in without being recognized and raising the alarm. The spy could check the weapons store and report back. Then we'll know for sure."&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WK9JH_L1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2019/12/pablo--8-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WK9JH_L1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2019/12/pablo--8-.png" alt="The Spy of Testadel: A Medieval Testing Tale" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And so it is decided, a spy will be sent to Sir SideEffects' camp, with the difficult mission of infiltrating the camp and gathering vital information. Thankfully, you know just the man for the job. Your court jester, aptly nicknamed Jest, is a master of disguise and despite what some might think, an intelligent and resourceful man.&lt;/p&gt;

&lt;p&gt;Later, as you go over the mission's plan with Jest, he points out a problem with the plan. If he is to somehow infiltrate the camp under the guise of one of its inhabitants, an opportunity for a swap must be created. At the moment, such an exchange is impossible as all of the camp's residents remain inside day and night.&lt;/p&gt;

&lt;p&gt;"Leave that up to me," you say, "I know just what to do. I'll send forged orders to Sir SideEffects' scribe requiring him to leave the camp for the day. Upon his return, you can intercept him a short distance from the gate and take his place. You should be able to walk right through the front gate if your disguise is convincing enough."&lt;/p&gt;

&lt;p&gt;As Jest makes preparation for his departure, you arrange for the forged orders to be sent to Sir SideEffects' scribe.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SirSideEffectsCamp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;armoury&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Weapons&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;scribe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Scribe&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- Scribe now passes through gate&lt;/span&gt;

  &lt;span class="nf"&gt;reportWeaponsStock&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scribe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeWeaponsReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next day, exactly as planned, Jest lies in wait by the wayside, about half a league from SideEffects' camp. As the sun begins to set, he finally sights his target. The scribe, back from surveying Sir SideEffects' fields, can already taste the turnip and cabbage soup waiting for him at home. Lost in his thoughts, he pays no attention to his surroundings. As he passes by the bushes where Jest had been lying in wait, he receives a massive blow to the head and immediately falls to the ground, unconscious.&lt;/p&gt;

&lt;p&gt;Jest drags the scribe's limp body into the bushes, removes his clothing and adorns himself with the lavish clothes and accoutrement.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SirSideEffectsCamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should report having less than 50 weapons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Our spy mimicks the scribe's ability to 'writeWeaponsReport'&lt;/span&gt;
    &lt;span class="c1"&gt;// but makes sure to keep a copy of the report in his pocket&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spyScribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;writeWeaponsReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Weapons&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;spyScribe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- Keep copy of report in pocket&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;camp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SirSideEffectsCamp&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weaponsStock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;camp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reportWeaponsStock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weaponsStock&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeLessThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All that is left now is to walk through the front gate and take the scribe's place.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SirSideEffectsCamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should report having less than 50 weapons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spyScribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;writeWeaponsReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Weapons&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;spyScribe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;camp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SirSideEffectsCamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spyScribe&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- Spy infiltrates the camp&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weaponsStock&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;camp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reportWeaponsStock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;weaponsStock&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeLessThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next morning, your envoy shows up at the gate of Sir SideEffects' camp and asks for a report like he did every month since the end of the war. This time though, your spy is in place inside the camp and is able to observe the weapons stock from the inside.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SirSideEffectsCamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should report having less than 50 weapons&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spyScribe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;writeWeaponsReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Weapons&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;spyScribe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pocket&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;camp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SirSideEffectsCamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spyScribe&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;camp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reportWeaponsStock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spyScribe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pocket&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toBeLessThan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- Get spy's report&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Later that day, your spy manages to sneak out and report his findings. Although the report given by Sir SideEffects once again said that he only had 6 weapons in his armory, Jest reports that he in fact has close to 100 weapons in stock and that he has been willfully giving false reports.&lt;/p&gt;

&lt;p&gt;What's more, while in the camp, Jest has heard a troubling rumour. Word around the drinking well is that Sir SideEffects has taken to dark magic. Apparently, the rumour goes, Sir SideEffects is in possession of a magical artifact that allows him to communicate directly with anyone, however far removed from the camp they may be. The rumour even goes as far as to say that the artifact - some say it is called &lt;em&gt;The Console&lt;/em&gt;&lt;sup&gt;TM&lt;/sup&gt; - would allow him to communicate with mystical beings from another realm.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XAnFy37e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2019/12/pablo--9-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XAnFy37e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://blog.snowfrog.dev/content/images/2019/12/pablo--9-.png" alt="The Spy of Testadel: A Medieval Testing Tale" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Though this seems a little far-fetched, you do suspect Sir SideEffects is using the artifact to communicate with his old ally, Sir EvilScreen.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SirSideEffectsCamp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;armoury&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Weapons&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;scribe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Scribe&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;reportWeaponsStock&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scribe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeWeaponsReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`We now have &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; weapons, death to Testadel!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;-&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If only there was a way to intercept the messages being sent through this magical object. "My Lord," a croaked voice is heard from the back of the hall as a wizened old man steps forward, "my name is Sir Mockalot and through my travels and adventures, I have acquired an object that I believe may be of assistance".&lt;/p&gt;

&lt;p&gt;Sir Mockalot explains that he possesses an artifact called the &lt;em&gt;The Mocksole&lt;/em&gt;&lt;sup&gt;TM&lt;/sup&gt;. "It is said to have been forged together with &lt;em&gt;The Console&lt;/em&gt;&lt;sup&gt;TM&lt;/sup&gt; and to possess very similar properties. If we could substitute &lt;em&gt;The Console&lt;/em&gt;&lt;sup&gt;TM&lt;/sup&gt; with our own artifact, we would be the ones receiving Sir SideEffects' messages and he would be none the wiser".&lt;/p&gt;

&lt;p&gt;As Sir Mockalot, accompanied by Jest, your trusty jester / spy,  goes to his chamber to prepare &lt;em&gt;The Mocksole&lt;/em&gt;&lt;sup&gt;TM&lt;/sup&gt;  for delivery to Sir SideEffects camp,&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SirSideEffectsCamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should not be sending treasonous messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theMocksole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- Preparing the Mocksole&lt;/span&gt;
      &lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;you set to writing an accompanying note.&lt;/p&gt;

&lt;p&gt;"Dear Sir SideEffects, I was not able to hear your last message through &lt;em&gt;The Console&lt;/em&gt;&lt;sup&gt;TM&lt;/sup&gt; as the sound was all garbled. Please find attached to this note, a replacement artifact to be used in its stead. Sincerely, Lord EvilScreen."&lt;/p&gt;

&lt;p&gt;The next day, &lt;em&gt;The Mocksole&lt;/em&gt;&lt;sup&gt;TM&lt;/sup&gt; is found at the camp's gate and brought in. Sir SideEffects reads the note and complies with its message.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SirSideEffectsCamp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;armoury&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Weapons&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;scribe&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Scribe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;artifact&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- A console-like artifact at the gate&lt;/span&gt;

  &lt;span class="nf"&gt;reportWeaponsStock&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;scribe&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;writeWeaponsReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;armoury&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;artifact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`We now have &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; weapons, death to Testadel!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- Let's use it instead of the old console.&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything is now in place to intercept the messages, all you need to do is stand by and listen.&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SirSideEffectsCamp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;test&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should not be sending treasonous messages&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;theMocksole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;log&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;jest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;treasonousTalk&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;death to Testadel!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;camp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SirSideEffectsCamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;spyScribe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;theMocksole&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;camp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reportWeaponsStock&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;theMocksole&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;calls&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringMatching&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;treasonousTalk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Horror! It is as you feared, Sir SideEffects is planning a rebellion. Thanks to the valiant efforts of your subjects you are made aware of this fact before it is too late and can make preparations. Peace will have unfortunately been short-lived.&lt;/p&gt;

</description>
      <category>dependencyinjection</category>
      <category>dependencyinversionprinciple</category>
      <category>testing</category>
      <category>spies</category>
    </item>
    <item>
      <title>When Should You Use A Web Framework?</title>
      <dc:creator>Philippe Vaillancourt</dc:creator>
      <pubDate>Tue, 19 Mar 2019 03:07:05 +0000</pubDate>
      <link>https://forem.com/snowfrogdev/when-should-you-use-a-web-framework-21i6</link>
      <guid>https://forem.com/snowfrogdev/when-should-you-use-a-web-framework-21i6</guid>
      <description>&lt;p&gt;Starting a new web app project. Wary of bloated frameworks with a gabillion dependencies. I'm a relatively inexperienced developper and I often feel like I don't know what the heck is going on under the hood in a framework like Angular. Part of me wants to code closer to the browser API but at the same time I want to be efficient and not reinvent the wheel.&lt;/p&gt;

&lt;p&gt;I've read many posts like this one:&lt;/p&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/gypsydave5" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F67380%2Fc0c013a8-7b5f-47d1-9e1b-3997106c7c81.jpeg" alt="gypsydave5"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/gypsydave5/why-you-shouldnt-use-a-web-framework-3g24" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Why You Shouldn't Use A Web Framework&lt;/h2&gt;
      &lt;h3&gt;David Wickes ・ Jul 26 '18&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#webdev&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#framework&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#beginners&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#react&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;and if you take a look at the comment sections, you can see that most reasonable people, whether they tend to be pro-framework or not, agree that in certain cases, it does make sense to use a framework, or to not use one.&lt;/p&gt;

&lt;p&gt;Both sides go on at length explaining the pros and cons of using, or not using, a framework. The one thing that everyone just seem to never get into is WHEN, exactly should we use / not use a framework? Where is this imaginary threshold where one passes from "framework good for my project" to "framework bad for my project"? How do YOU make that determination? Where do YOU draw the line? Let's get into specifics. Examples. Level of complexity. Scope. Team size. &lt;/p&gt;

&lt;p&gt;You're pro-framework but are reasonable enough to admit that sometimes it makes sense to not use one? On what kind of project would you consider ditching the framework and go vanilla / few small libraries?&lt;/p&gt;

&lt;p&gt;You're anti-framework (looking at you &lt;a class="mentioned-user" href="https://dev.to/gypsydave5"&gt;@gypsydave5&lt;/a&gt;) but are reasonable enough to admit that sometimes it makes sense to use one? On what kind of project would you consider using a framework?&lt;/p&gt;

&lt;p&gt;You're of the opinion that one should NEVER / ALWAYS use a framework? Please avoid commenting on this post and consider adding to the lively discussion on &lt;a class="mentioned-user" href="https://dev.to/gypsydave5"&gt;@gypsydave5&lt;/a&gt; 's post instead. 😜&lt;/p&gt;

&lt;p&gt;Really interested to hear your diverse opinions.&lt;/p&gt;

</description>
      <category>discuss</category>
      <category>webdev</category>
      <category>frameworks</category>
    </item>
  </channel>
</rss>
