<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  
  <title>Mario Pabon</title>
  <subtitle>Mario Pabon is a full stack software engineer in Brooklyn, NYC with 12 years of experience building web and iOS apps. Read his writing and see his projects.</subtitle>
  <link href="https://mariopabon.com/feed.xml" rel="self" />
  <link href="https://mariopabon.com/" />
  <updated>2025-08-06T00:00:00Z</updated>
  <id>https://mariopabon.com/</id>
  <author>
    <name>Mario Pabon</name>
  </author>
  <entry>
    <title>Assembling your software engineering toolkit</title>
    <link href="https://mariopabon.com/writings/toolkit/" />
    <updated>2025-08-06T00:00:00Z</updated>
    <id>https://mariopabon.com/writings/toolkit/</id>
    <content type="html">&lt;p&gt;At some point during a long career of building software, you reach a level of experience that allows you to identify the right tools and patterns to use the moment you&#39;re presented with a new problem. The products you are building may be different, but you start to recognize patterns from features you&#39;ve already built, and building becomes more of an exercise of figuring out how to best fit things together than how to execute lower level details.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A tool in the context of software engineering could be a package of code, architectural pattern, or a program that does some of your work for you.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ideally, this toolkit you&#39;re assembling should be more than just a collection of items you had a great time with; they should help you do your job better. Therefore the value of a tool depends on what your definition of doing your job &amp;quot;better&amp;quot; is.&lt;/p&gt;
&lt;h2&gt;The Good Tool&lt;/h2&gt;
&lt;p&gt;To me, doing my job better means shipping quickly with a high-level of quality, while having done as little of my own work as possible. If this is something you&#39;re aligned with, the tools you pick should be ones that help you ship good products faster. Here are some of the attributes of tools that enable this:&lt;/p&gt;
&lt;h3&gt;1. Part of a vibrant ecosystem.&lt;/h3&gt;
&lt;p&gt;If you want to move quickly, the best way to do so is by standing on the shoulders of giants, ideally on top of those who are already in motion with their big, long, giant legs.&lt;/p&gt;
&lt;p&gt;Choosing tools that are a part of a mature and open-source ecosystem means you&#39;ll have a vast library of code you can incorporate into your project, along with a ton of relevant StackOverflow and GitHub Issues, and the ability to get your hands dirty to contribute yourself when necessary.&lt;/p&gt;
&lt;p&gt;This could mean picking a battle-tested framework such as Django or Ruby on Rails. Both of them have been around since the beginning of time and will have most of your needs taken care of already, implemented either directly into the framework itself or installable as a package or gem.&lt;/p&gt;
&lt;p&gt;This could also mean avoiding less popular or mature frameworks. You won&#39;t have the same level of support and will be on your own if you have a question or run into any issues.&lt;/p&gt;
&lt;h3&gt;2. Makes low-level decisions for you.&lt;/h3&gt;
&lt;p&gt;When building a product or service, you have better things to think about than where to put a new file or how to wire up your API to your database. Ideally, these types of decisions are made at the beginning of your project and rarely revisited.&lt;/p&gt;
&lt;p&gt;Even better, you can leverage a framework or architectural pattern that makes these decisions for you, so you can focus on the core issue at hand. This could look like using an opinionated framework such as Rails, or adhering to the gospel of Domain Driven Design.&lt;/p&gt;
&lt;h3&gt;3. Lets you own your data and product.&lt;/h3&gt;
&lt;p&gt;If you want to maintain the ability to control how your product works and looks, you should avoid handing over control of mission critical functionality to external providers. Otherwise you&#39;ll be at their whim and limited by the functionality they offer. And if they don&#39;t offer good customization options, you can end up writing a lot of code massaging it into a form that&#39;s almost close to what you need it to be.&lt;/p&gt;
&lt;p&gt;One feature this happens frequently with is auth. There are plenty of services out there that will gladly sell you an exponentially expensive auth solution in exchange for added complexity and slowness in your app. You should instead prefer packages that let you integrate auth directly into your product and database while still handling the underlying complexity for you, such as &lt;a class=&quot;external-link icon-link&quot; href=&quot;https://openauth.js.org/docs/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;OpenAuth&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; shape-rendering=&quot;crispEdges&quot; class=&quot;icon icon-end&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M14 2h8v1H14zM14 3h8v1H14zM18 4h4v1H18zM3 5h9v1H3zM17 5h5v1H17zM2 6h10v1H2zM16 6h3v1H16zM20 6h2v1H20zM2 7h2v1H2zM15 7h3v1H15zM20 7h2v1H20zM2 8h2v1H2zM14 8h3v1H14zM20 8h2v1H20zM2 9h2v1H2zM13 9h3v1H13zM20 9h2v1H20zM2 10h2v1H2zM12 10h3v1H12zM2 11h2v1H2zM11 11h3v1H11zM2 12h2v1H2zM10 12h3v1H10zM17 12h2v1H17zM2 13h2v1H2zM9 13h3v1H9zM17 13h2v1H17zM2 14h2v1H2zM9 14h2v1H9zM17 14h2v1H17zM2 15h2v1H2zM17 15h2v1H17zM2 16h2v1H2zM17 16h2v1H17zM2 17h2v1H2zM17 17h2v1H17zM2 18h2v1H2zM17 18h2v1H17zM2 19h2v1H2zM17 19h2v1H17zM2 20h17v1H2zM3 21h15v1H3z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;
or &lt;a class=&quot;external-link icon-link&quot; href=&quot;https://docs.allauth.org/en/latest/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Django Allauth&lt;svg xmlns=&quot;http://www.w3.org/2000/svg&quot; viewBox=&quot;0 0 24 24&quot; fill=&quot;currentColor&quot; shape-rendering=&quot;crispEdges&quot; class=&quot;icon icon-end&quot; aria-hidden=&quot;true&quot;&gt;&lt;path d=&quot;M14 2h8v1H14zM14 3h8v1H14zM18 4h4v1H18zM3 5h9v1H3zM17 5h5v1H17zM2 6h10v1H2zM16 6h3v1H16zM20 6h2v1H20zM2 7h2v1H2zM15 7h3v1H15zM20 7h2v1H20zM2 8h2v1H2zM14 8h3v1H14zM20 8h2v1H20zM2 9h2v1H2zM13 9h3v1H13zM20 9h2v1H20zM2 10h2v1H2zM12 10h3v1H12zM2 11h2v1H2zM11 11h3v1H11zM2 12h2v1H2zM10 12h3v1H10zM17 12h2v1H17zM2 13h2v1H2zM9 13h3v1H9zM17 13h2v1H17zM2 14h2v1H2zM9 14h2v1H9zM17 14h2v1H17zM2 15h2v1H2zM17 15h2v1H17zM2 16h2v1H2zM17 16h2v1H17zM2 17h2v1H2zM17 17h2v1H17zM2 18h2v1H2zM17 18h2v1H17zM2 19h2v1H2zM17 19h2v1H17zM2 20h17v1H2zM3 21h15v1H3z&quot;&gt;&lt;/path&gt;&lt;/svg&gt;&lt;/a&gt;
.&lt;/p&gt;
&lt;h3&gt;4. You know it inside and out.&lt;/h3&gt;
&lt;p&gt;The best tool is usually the one you already know. Otherwise, you&#39;ll find yourself trying to learn a new tool at the same time you are figuring out the thing you are building. This will slow you down and be incredibly frustrating.&lt;/p&gt;
&lt;p&gt;If you&#39;re trying to replace a tool that you&#39;ve used before and have determined sucks, I recommend trying it out in a new side-project, or in a limited portion of an already well-established product.&lt;/p&gt;
&lt;p&gt;One example of where trying out a new tool went well for me was introducing type-checking into a very large Python codebase that was shared by multiple teams. Rather than trying to get complete code coverage and slow everyone down with an unfamiliar tool, I set it up to check just one directory at first, and then slowly expanded coverage from there as the team built confidence and became more comfortable with mypy.&lt;/p&gt;
&lt;h2&gt;Finding new tools&lt;/h2&gt;
&lt;p&gt;If staying relevant is important to you, you&#39;ll want to periodically step outside your comfort zone and see what else is out there.&lt;/p&gt;
&lt;p&gt;I do this by subscribing to all the &lt;code&gt;&amp;lt;X&amp;gt; Weekly&lt;/code&gt; newsletters, such as React Weekly or Django Weekly, and bookmarking or GitHub starring anything that piques my interest. I&#39;ll revisit this list whenever I have the urge to build something new, or if I have a need for them in something I&#39;m already building.&lt;/p&gt;
&lt;p&gt;If you&#39;re part of a lively ecosystem like Python or JavaScript, it&#39;s easy to become overwhelmed by the constant deluge of new tools and services being released, and maybe even feel like you&#39;re becoming a dinosaur by sticking to the ones already in your toolkit.&lt;/p&gt;
&lt;p&gt;At the end of the day, customers could care less how you built your product—only that it works and solves their problem.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Easy and fun dependency injection with TypeScript</title>
    <link href="https://mariopabon.com/writings/typescript-dependency-injection/" />
    <updated>2025-02-25T00:00:00Z</updated>
    <id>https://mariopabon.com/writings/typescript-dependency-injection/</id>
    <content type="html">&lt;p&gt;&lt;em&gt;In the beginning, there was only Chaos… then out of the void, appeared [the dependency inversion principle].&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;I found myself quoting these very words recently after refactoring a project of mine that I hadn’t touched in months. After a while of receiving and then promptly ignoring user requests for new features, I had decided to finally revisit it and give the people what they wanted. Unfortunately though, what I came back to was an impenetrable rat’s nest of imports and function calls, written by someone who presumably did not give a metaphorical “rat’s ass” about SOLID principles or testability.&lt;/p&gt;
&lt;p&gt;Here’s a small sample of what I was up against. In this function, we are sending one of those “magic link” emails that lets someone login to their account with a single click. It’ll also create someone’s account for them if we receive an email address we don’t have in our system yet. How convenient!&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;figure class=&quot;code-block&quot;&gt;&lt;figcaption class=&quot;code-block-title cursor-skip&quot;&gt;bad-code.ts&lt;/figcaption&gt;&lt;pre class=&quot;shiki ayu-dark&quot; style=&quot;background-color:#0d1017;color:#bfbdb6&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; config &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;@server/config&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { buildLoginEmail } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;@server/emails/log-in&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; mailer &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;@server/services/mailer&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { getOrCreateUserFromEmail } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;./accounts&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { User } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;@prisma/client&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; function&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; sendLogInEmail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#39BAE6&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; user &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; getOrCreateUserFromEmail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(email)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; token &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; createAuthToken&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(user&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;id)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#5A6673;font-style:italic&quot;&gt;  // Build login url&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; params &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; URLSearchParams&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;    token&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; encodeURIComponent&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(token)&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; loginUrl &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F29668&quot;&gt;    new&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; URL&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt;&quot;/api/auth/email&quot;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; config&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt;&quot;appUrl&quot;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;))&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;() &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;+&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt;    &quot;?&quot;&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt; +&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;    params&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;toString&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; loginEmail &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; buildLoginEmail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;({ loginUrl })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  return&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; mailer&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;sendMail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F29668&quot;&gt;    ...&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;loginEmail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;    from&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;Wordler &amp;#x3C;no-reply@wordler.xyz&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;    to&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; user&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To be fair, this block of code maybe isn’t as hellish as I originally remembered. But it does pose a few challenges in terms of reusability and testability, and thus will serve just fine for the purpose of this write-up.&lt;/p&gt;
&lt;p&gt;Firstly, it’s doing too much. This function is called “send log in email”, but it also has a fun side-effect of potentially creating a new user account. This makes it difficult to test the email generation logic on its own without first needing to setup a database. And if we decided we wanted to send a log in email for an account that we’ve already loaded from the database somewhere else? Nah, you’re querying for it again, whether you like it or not.&lt;/p&gt;
&lt;p&gt;Secondly, it’s importing its own dependencies, via what are essentially global variables assigned by the import keyboard. This will make testing this function even more difficult, as we would have to ensure that those dependencies are mocked before this function uses them, or somehow mess with the import system in some nasty way to get it to point to mock versions.&lt;/p&gt;
&lt;p&gt;So, before I began adding new functionality, I wanted to make sure that I wouldn’t be consumed by the chaos void created from this tight coupling of components that I would need to re-use, and I wanted to add some tests for the existing functionality to make sure I wasn’t breaking things as I worked. In short, I needed to:&lt;/p&gt;
&lt;p&gt;Refactor the existing code to make it more reusable for the new stuff I would be building.&lt;/p&gt;
&lt;p&gt;Make the code testable, so that I could actually write tests for it.&lt;/p&gt;
&lt;p&gt;It turns out that these two objectives go hand-in-hand: well structured code is testable, and testable code is well structured. It also turns out these two things are what dependency injection was basically born to do.&lt;/p&gt;
&lt;h2&gt;Why DI&lt;/h2&gt;
&lt;p&gt;At its essence, I think of dependency injection as the practice of programming against some interface, and then injecting an implementation of that interface when needed. There’s a lot more to it than that of course- if you’re interested in diving deeper into theory, I highly recommend you check out this article that has been aptly titled Inversion of Control Containers and the Dependency Injection pattern by our favorite Java Head, Martin Fowler.&lt;/p&gt;
&lt;p&gt;But we like to be as practical as possible here on coquito.io, so let’s dig into some code. We&#39;re going to see how we can make that send log in email function more modular using dependency injection, using my favorite package for handling DI in TypeScript, TypeDI. Let&#39;s start by breaking up our concerns into separate &amp;quot;service&amp;quot; classes:&lt;/p&gt;
&lt;pre class=&quot;shiki ayu-dark&quot; style=&quot;background-color:#0d1017;color:#bfbdb6&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { Service } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;typedi&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { Account } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;@prisma/client&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#5A6673;font-style:italic&quot;&gt;// type Account = { email: string; id: string; }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6C08A&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;Service&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; AccountService&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; findOrCreateWithEmail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#39BAE6&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; Promise&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt;Account&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#5A6673;font-style:italic&quot;&gt;    // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6C08A&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;Service&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; AuthService&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; sendLogInEmail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt;account&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; Account&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; Promise&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#39BAE6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#5A6673;font-style:italic&quot;&gt;    // ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We&#39;ve identified two areas of concern: managing user accounts, and managing authentication. You may have also noticed those little &lt;code&gt;@Service()&lt;/code&gt; decorators applied to each class: these tell TypeDI that we want these service classes to be auto-injected when we specify any of them as a dependency- more on that in a bit.&lt;/p&gt;
&lt;p&gt;These services have dependencies of their own: a database connection, and a way to send emails. Let&#39;s add services for those now:&lt;/p&gt;
&lt;pre class=&quot;shiki ayu-dark&quot; style=&quot;background-color:#0d1017;color:#bfbdb6&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { Service } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;typedi&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { PrismaClient } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;@prisma/client&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { Transporter&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; createTransport } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;nodemailer&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6C08A&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;Service&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; DatabaseService&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  protected&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; _connection&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; PrismaClient&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#39BAE6;font-style:italic&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;_connection &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; PrismaClient&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; connection&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#39BAE6;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;_connection&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6C08A&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;Service&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; MailerService&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  private&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; _transport&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; Transporter&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#39BAE6;font-style:italic&quot;&gt;    this&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;_transport &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; createTransport&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;      host&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;smtp.sendgrid.net&quot;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;      port&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt; 465&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;      secure&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;      auth&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;        user&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;apikey&quot;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;        pass&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; process&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;env&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;SENDGRID_API_KEY&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;      }&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;    })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; get&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; transport&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;() {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#39BAE6;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;_transport&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let&#39;s use these new services to implement our account and auth services:&lt;/p&gt;
&lt;pre class=&quot;shiki ayu-dark&quot; style=&quot;background-color:#0d1017;color:#bfbdb6&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { Service } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;typedi&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { Account } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;@prisma/client&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { DatabaseService } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;./database-service&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { MailerService } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;./mailer-service&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6C08A&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;Service&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; AccountService&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt; databaseService&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; DatabaseService&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;) {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; findOrCreateWithEmail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt;email&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#39BAE6&quot;&gt; string&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; Promise&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt;Account&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; existingAccount &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;      await&lt;/span&gt;&lt;span style=&quot;color:#39BAE6;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;databaseService&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;connection&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;account&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;findFirst&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;({&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;        where&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { email }&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;      })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#5A6673;font-style:italic&quot;&gt;    // Return existing account or create a new one&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#E6C08A&quot;&gt;@&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;Service&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;export&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; class&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; AuthService&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  constructor&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;private&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt; mailerService&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; MailerService&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;) {}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  public&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; sendLogInEmail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt;account&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; Account&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;)&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; Promise&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;&amp;#x3C;&lt;/span&gt;&lt;span style=&quot;color:#39BAE6&quot;&gt;void&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#5A6673;font-style:italic&quot;&gt;    // Generate auth token and login url...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#39BAE6;font-style:italic&quot;&gt; this&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;mailerService&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;transport&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;sendMail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;({ to&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; account&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;email &lt;/span&gt;&lt;span style=&quot;color:#5A6673;font-style:italic&quot;&gt;/* ... */&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wow! Look look at that separation of concerns. Now the account service is only worried about managing accounts, and the authentication service is only worried about handling authentication. Let&#39;s see how this all comes together in an Express handler:&lt;/p&gt;
&lt;pre class=&quot;shiki ayu-dark&quot; style=&quot;background-color:#0d1017;color:#bfbdb6&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { Container } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;typedi&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { AccountService&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; AuthService } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;./services&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;const&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; authenticateUser&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; (&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt;req&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt; res&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;) &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; accountService &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; Container&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(AccountService)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; authService &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; Container&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(AuthService)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; account &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; await&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; accountService&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;findOrCreateWithEmail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(req&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;body&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;email)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;  await&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; authService&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;sendLogInEmail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(account)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  res&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;json&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;({ sent&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt; true&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Here, we&#39;ve defined our handler as a plain old function, and are retrieving instances of our services with TypeDI&#39;s Container API.&lt;/p&gt;
&lt;p&gt;TypeDI works by registering anything you&#39;ve decorated with @Service() into a global &amp;quot;container&amp;quot;. These services are treated as singletons, and are only instantiated the first time you request them using Container.get(ServiceClass) . TypeDI will also auto-inject any services that are specified as a dependency in another service&#39;s constructor.&lt;/p&gt;
&lt;p&gt;This makes managing all of our dependencies a breeze, as it means we don&#39;t need to manually construct our services and their dependencies, along with the dependencies of those dependencies. This is happening here for AccountService and AuthService , where each automatically received an instance of DatabaseService and MailerService.&lt;/p&gt;
&lt;p&gt;You can of course instantiate your own services manually, since they are just classes. TypeDI also allows you to replace a registered service with a different implementation, via Container.set(ServiceClass, NewImplementation). This is particularly useful for testing.&lt;/p&gt;
&lt;h2&gt;Better testing&lt;/h2&gt;
&lt;p&gt;Now it&#39;s time to take a look at how this pattern is useful for testing. A common task in test code is swapping or mocking dependencies that talk to external resources, like a database or an email transport. Because our services are only relying on the interfaces of other services and not directly importing their own implementations, this is fairly straightforward. Here&#39;s an example, with Jest:&lt;/p&gt;
&lt;pre class=&quot;shiki ayu-dark&quot; style=&quot;background-color:#0d1017;color:#bfbdb6&quot; tabindex=&quot;0&quot;&gt;&lt;code class=&quot;language-typescript&quot;&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { Container } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;typedi&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { Account } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;@prisma/client&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { describe&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; it&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; expect&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; jest } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;@jest/globals&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { AuthService } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;./services&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; { MailerService } &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;./mailer-service&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;describe&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt;&quot;AuthService.sendLogInEmail&quot;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;  it&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt;&quot;should send an email&quot;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt; async&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; () &lt;/span&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;=&gt;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#5A6673;font-style:italic&quot;&gt;    // Arrange&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; account&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#59C2FF&quot;&gt; Account&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt; =&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;      id&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;test_id&quot;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;      email&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;:&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;test@test.net&quot;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; mailerService &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; Container&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;get&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(MailerService)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; sendMailSpy &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; jest&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F29668&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;spyOn&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(mailerService&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;transport&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6B3&quot;&gt;,&lt;/span&gt;&lt;span style=&quot;color:#AAD94C&quot;&gt; &quot;sendMail&quot;&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#F29668&quot;&gt;      .&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;mockResolvedValueOnce&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;({})&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;    const&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; authService &lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt; new&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt; AuthService&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(mailerService)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#5A6673;font-style:italic&quot;&gt;    // Act&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FF8F40&quot;&gt;    await&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt; authService&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;sendLogInEmail&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(account)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#5A6673;font-style:italic&quot;&gt;    // Assert&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;    expect&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(sendMailSpy)&lt;/span&gt;&lt;span style=&quot;color:#F29668&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#FFB454&quot;&gt;toHaveBeenCalledTimes&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#D2A6FF&quot;&gt;1&lt;/span&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#5A6673;font-style:italic&quot;&gt;    // You could also assert the email body is correct and whatnot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;  })&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#BFBDB6&quot;&gt;})&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Wonderful. Powerful, even.&lt;/p&gt;
&lt;h2&gt;Alternative approaches&lt;/h2&gt;
&lt;p&gt;For political reasons I should probably mention some alternative packages besides TypeDI. In my experience TypeDI is the most straightforward to work with, but you should shop around and decide for yourself:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;microsoft/tsyringe&lt;/li&gt;
&lt;li&gt;jeffijoe/awilix&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And also, the example in this post is using classes, but this concept can also be applied using functions, where they would accept their dependencies as arguments. I am personally very satisfied with this class-based approach though, so I&#39;ll let you figure out the intricacies of using functions instead on your own :).&lt;/p&gt;
&lt;h2&gt;Summing up&lt;/h2&gt;
&lt;p&gt;I hope I’ve convinced you of the magic of dependency injection, and of how powerful a tool it can be for helping you write code that is well structured, composable, and easy to test.&lt;/p&gt;
&lt;p&gt;If you’re struggling to tame your own personal rat’s nest of imports and coupled functions, I highly recommend giving dependency injection a shot (ha!)&lt;/p&gt;
</content>
  </entry>
</feed>