<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Daniel Buckmaster</title>
    <description>The latest articles on DEV Community by Daniel Buckmaster (@crabmusket).</description>
    <link>https://dev.to/crabmusket</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%2F129464%2Ff3cde7e4-4bfc-40b8-972f-3dd8a11ee9c4.jpg</url>
      <title>DEV Community: Daniel Buckmaster</title>
      <link>https://dev.to/crabmusket</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/crabmusket"/>
    <language>en</language>
    <item>
      <title>How I Learned OOP: A Nightmare</title>
      <dc:creator>Daniel Buckmaster</dc:creator>
      <pubDate>Tue, 05 Oct 2021 01:00:39 +0000</pubDate>
      <link>https://dev.to/crabmusket/how-i-learned-oop-a-nightmare-4hdc</link>
      <guid>https://dev.to/crabmusket/how-i-learned-oop-a-nightmare-4hdc</guid>
      <description>&lt;p&gt;C++ was the first Object Oriented programming language. It was created by mixing C with Simula, which was invented by Alan Kay. In this article, I'll be sharing some helpful principles I was taught for writing OOP programs.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Use inheritance to share behaviour&lt;/li&gt;
&lt;li&gt;Create deep inheritance hierarchies&lt;/li&gt;
&lt;li&gt;Provide a getter for every private member&lt;/li&gt;
&lt;li&gt;Mutable state is your friend&lt;/li&gt;
&lt;li&gt;A class must be something you can touch&lt;/li&gt;
&lt;li&gt;You can touch &lt;code&gt;Bean&lt;/code&gt;s&lt;/li&gt;
&lt;li&gt;OOP is the only paradigm you'll ever need&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Without further ado, let's begin!&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Use inheritance to share behaviour
&lt;/h2&gt;

&lt;p&gt;As we all know, inheritance is the best way to share behaviour and reduce code duplication (after all, if you're not DRY, you're MOIST).&lt;/p&gt;

&lt;p&gt;Let's say you have a &lt;code&gt;Parrot&lt;/code&gt; class which can &lt;code&gt;talk&lt;/code&gt;, and a &lt;code&gt;SpeakAndSpell&lt;/code&gt; which can also &lt;code&gt;talk&lt;/code&gt;. Obviously, they should both inherit from a common base class so you don't have to duplicate the &lt;code&gt;talk&lt;/code&gt; method! &lt;code&gt;class Parrot extends AbstractBaseTalker&lt;/code&gt; and &lt;code&gt;class SpeakAndSpell extends AbstractBaseTalker&lt;/code&gt; looks so clean, doesn't it?&lt;/p&gt;

&lt;p&gt;Since we've been so successful at using inheritance to solve this duplicated code, doesn't it make you want to use &lt;em&gt;more&lt;/em&gt; inheritance? Well, you're in luck, because our next OOP best practise is:&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Create deep inheritance hierarchies
&lt;/h2&gt;

&lt;p&gt;The more code you write, the more risk there is of duplication. So as your app grows, that means that the depth and length of your inheritance chains should also grow.&lt;/p&gt;

&lt;p&gt;(Though I prefer to think of them not as "chains", which sounds like a you're in a dungeon, but rather "inheritance twizzlers", because twizzlers are long like chains, but are delicious, not like chains.)&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Provide a getter for every private member
&lt;/h2&gt;

&lt;p&gt;As we all know, in OOP when a data member is private, this means we have to provide some way for other objects to access the member! This means you should always add a getter for your private data members. This is known as encapsulation.&lt;/p&gt;

&lt;p&gt;Oh, and don't forget to add setters for all private data members too, because:&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Mutable state is your friend
&lt;/h2&gt;

&lt;p&gt;In the real world, things change. And because OOP is all about taking objects that exist in the real world and turning them directly into code, that means our code-objects should change too! Put the past behind you and throw caution to the wind, because OOP will free you from worrying about what something &lt;em&gt;used&lt;/em&gt; to be. All that matters is what it is now.&lt;/p&gt;

&lt;p&gt;When I said "OOP is all about taking objects that exist in the real world and turning them directly into code", I wasn't kidding:&lt;/p&gt;

&lt;h2&gt;
  
  
  5. A class must be something you can touch
&lt;/h2&gt;

&lt;p&gt;OOP is all about modelling the real world. Every application should be like a video game full of little objects being born, frolicking about, reproducing, and eventually dying. You can't create such an application if your classes represent intangible things. Each class should be a representation of something you can &lt;em&gt;touch!&lt;/em&gt; Like &lt;code&gt;User&lt;/code&gt;, &lt;code&gt;Pet&lt;/code&gt;, &lt;code&gt;Car&lt;/code&gt;, and &lt;code&gt;Square&lt;/code&gt;*.&lt;/p&gt;

&lt;p&gt;Sticking to this means that your application will be more maintainable, because literally every single thing that a &lt;code&gt;User&lt;/code&gt; can ever do (or have done to them) will now be in one easy-to-find location!&lt;/p&gt;

&lt;p&gt;&lt;em&gt;*As long as the square is like, made of concrete or paint or twigs or something. Abstract shapes are a no-go. See the next tip for what to do if you really have to work with abstract shapes.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  6. You can touch &lt;code&gt;Bean&lt;/code&gt;s
&lt;/h2&gt;

&lt;p&gt;If you really have to write code for something intangible (like &lt;code&gt;Happiness&lt;/code&gt;, &lt;code&gt;Red&lt;/code&gt; or &lt;code&gt;EmployeeTerminationProcedure&lt;/code&gt;), you should end the class name with &lt;code&gt;Bean&lt;/code&gt;, because you can touch beans! This trick ensures that every class in your application represents something tangible. No more abstract &lt;code&gt;Happiness&lt;/code&gt; just floating around in the ether; the &lt;code&gt;HappinessBean&lt;/code&gt; is something you can really feel, see, and taste.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Factory&lt;/code&gt; is also good for this, because a factory is also something you can touch. But factories are large, complicated, smelly and dangerous, so it's up to you whether you want that whole vibe in your codebase.&lt;/p&gt;

&lt;p&gt;But this final lesson I was taught about OOP is the most important:&lt;/p&gt;

&lt;h2&gt;
  
  
  7. OOP is the only paradigm you'll ever need
&lt;/h2&gt;

&lt;p&gt;If you mix OOP with functional programming, or if you use structs-of-arrays, the ghost of James Gosling (inventor of C++) will find you and give you a good scolding, like in that Dickens novel. Because what you're doing is basically ruining Christmas for us all.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed this advice. Now go forth and code! And most importantly, in about 3-4 years please write a blog post about how I promised you that OOP would solve all your problems, but in reality it just helped you create an enormous spaghettified mess. This is an important part of the OOP journey.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is satire...
&lt;/h2&gt;

&lt;p&gt;...or is it? Looking around the web, you'd think this is exactly how OOP has been taught. There are a plethora of blog posts that use awful examples like &lt;code&gt;class Dog extends Pet&lt;/code&gt;. Inheritance is introduced immediately after the &lt;code&gt;class&lt;/code&gt; keyword, setters and getters abound, and people treat C++ and Java as if they have &lt;em&gt;anything&lt;/em&gt; in common with Smalltalk, Ruby or Python.&lt;/p&gt;

&lt;p&gt;OOP education needs a reformation, &lt;em&gt;now&lt;/em&gt;. Sandi Metz can't do it all by herself!&lt;/p&gt;

&lt;p&gt;I wrote this post because I frequently see bad arguments about why OOP sucks. OOP does indeed suck at many things - but for good reasons, not bad reasons. If OOP education were better, then maybe people could discuss these things with more sense and less nonsense.&lt;/p&gt;

&lt;p&gt;And maybe if people had a clearer-eyed sense of the benefits and pitfalls of OOP, unobstructed by awful advice like the 7 points above, they would be less bitter and disappointed when they reach the inevitable limits of one paradigm. And less naive and starry-eyed about the next hot paradigm, whatever it happens to be.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Photo by &lt;a href="https://unsplash.com/@homajob?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Scott Graham&lt;/a&gt; on &lt;a href="https://unsplash.com/s/photos/business?utm_source=unsplash&amp;amp;utm_medium=referral&amp;amp;utm_content=creditCopyText"&gt;Unsplash&lt;/a&gt;. And yes, I did once see someone post about Simula being invented by Alan Kay.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>oop</category>
      <category>java</category>
      <category>learning</category>
      <category>satire</category>
    </item>
    <item>
      <title>A stateless token case study: Algolia search API</title>
      <dc:creator>Daniel Buckmaster</dc:creator>
      <pubDate>Sun, 06 Dec 2020 01:45:34 +0000</pubDate>
      <link>https://dev.to/crabmusket/a-stateless-token-case-study-algolia-search-api-27pk</link>
      <guid>https://dev.to/crabmusket/a-stateless-token-case-study-algolia-search-api-27pk</guid>
      <description>&lt;p&gt;At work, we use Algolia to outsource the job of managing search infrastructure. One part of its API intrigued me. Algolia's server-side library allows us to create &lt;a href="https://www.algolia.com/doc/api-reference/api-methods/generate-secured-api-key/" rel="noopener noreferrer"&gt;"secured API keys"&lt;/a&gt; to give to our users (i.e., browsers), with which our users can perform searches over our Algolia data with filters.&lt;/p&gt;

&lt;p&gt;For example, our Algolia account contains search data from Teams A, B and C. When a user from Team A logs in, our server generates an Algolia token for that user with a filter set to only show results from Team A's data.&lt;/p&gt;

&lt;p&gt;The cool thing is, these secured tokens can be created without any calls to Algolia's servers, making them very lightweight and easy to use. I wanted to find out how Algolia were actually doing it! Having been reading a lot about JWTs and trying them out on some APIs, I wanted to discover a good use-case for them. This seemed similar enough - but I could tell that what Algolia was creating were &lt;em&gt;not&lt;/em&gt; actual JWTs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Investigating the code
&lt;/h2&gt;

&lt;p&gt;In our app, creating a "secured token" looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$searchToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SearchClient&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;generateSecuredApiKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$secret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'filters'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'team:'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;team_id&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 the example, &lt;code&gt;$secret&lt;/code&gt; is a server-side configuration value Algolia gives us, which we never share with clients. &lt;code&gt;$searchToken&lt;/code&gt; gets sent to the client's browser on page load. Because creating a token doesn't require any API calls, we create new tokens on every page load, and could quickly refresh or modify them during a session if we needed to.&lt;/p&gt;

&lt;p&gt;To work out what was actually contained in these tokens, I went digging in the source code of their PHP library. I found the relevant code &lt;a href="https://github.com/algolia/algoliasearch-client-php/blob/bfb5e4e7e64a99260c4975c46de29eea5f072d71/src/SearchClient.php#L243-L250" rel="noopener noreferrer"&gt;here&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;generateSecuredApiKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$parentApiKey&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$restrictions&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$urlEncodedRestrictions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Helpers&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;buildQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$restrictions&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nv"&gt;$content&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;hash_hmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sha256'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$urlEncodedRestrictions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$parentApiKey&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nv"&gt;$urlEncodedRestrictions&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;base64_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$content&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 the token that gets sent to a client will be structured something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;base64_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;hash_hmac&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'sha256'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'filters=team%3A123'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'secret'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'filters=team%3A123'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which will simplify further to something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nb"&gt;base64_encode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s1"&gt;'8b02da15d77ee56bf593849cb4ca8494f2cff19403c8c0bd99fc362e91a5ec69'&lt;/span&gt;
    &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'filters=team%3A123'&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And, after base64 encoding, it will appear as a string like this:&lt;br&gt;
&lt;/p&gt;

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

&lt;/div&gt;



&lt;p&gt;The important points to note are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;base64&lt;/code&gt; is reversible, so the final string can be converted back into the second-to-last step by &lt;em&gt;anyone&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sha256&lt;/code&gt; is &lt;em&gt;not reversible&lt;/em&gt;, so nobody can work out what &lt;code&gt;'secret'&lt;/code&gt; is&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The cool part about this is that the token contains a mix of usable data (the query-encoded data at the end of the string) and unusable data (the &lt;code&gt;sha256&lt;/code&gt; hash at the beginning).&lt;/p&gt;

&lt;p&gt;When one of our users sends the token back to Algolia's servers as part of a search request, Algolia's server can do two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It can work out what filters to apply, based on the usable query-string data&lt;/li&gt;
&lt;li&gt;It can check that the hash matches the filters that were asked for&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first step provides &lt;em&gt;functionality:&lt;/em&gt; being able to apply a filter to a search. The second step provides &lt;em&gt;security:&lt;/em&gt; making sure that nobody messed with the filters between when we created the token and when Algolia received it.&lt;/p&gt;

&lt;p&gt;The client could base64 decode the token and grab the query parameter data if it wanted. But if it tried to change the filters and send the request on to Algolia, the first part of the data, the hash, would no longer match. Algolia would know the request had been tampered with, and would refuse to fulfil it.&lt;/p&gt;

&lt;h2&gt;
  
  
  If it quacks like a JWT
&lt;/h2&gt;

&lt;p&gt;These Algolia tokens obviously don't include any JSON; they encode their payload data as a URL query string instead. But you could achieve a similar result using a JWT. Both are ways to send data between two trusted services via an untrusted intermediary.&lt;/p&gt;

&lt;p&gt;The data is unencrypted, so the client can inspect the data. But because of the cryptographic signature attached to the data, the client cannot &lt;em&gt;modify&lt;/em&gt; the data without detection.&lt;/p&gt;

&lt;p&gt;The general principle works like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcrabmusket.net%2Fimages%2Fstatelesstoken.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcrabmusket.net%2Fimages%2Fstatelesstoken.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We copy the secret token from Algolia to our servers "manually" (or via config management software)&lt;/li&gt;
&lt;li&gt;Our server creates a secured token for a specific user when that user needs to search, with parameters specific to that user&lt;/li&gt;
&lt;li&gt;The token is shared with the client&lt;/li&gt;
&lt;li&gt;The client uses the token, as well as other identifying information, to make requests directly to Algolia&lt;/li&gt;
&lt;li&gt;Algolia checks that the token is correct (has not been tampered with), then extracts the parameters and performs the query the client requested&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Beyond the initial sharing of the secret between Algolia and our own servers, we don't need to send requests to Algolia's API; the client can communicate with them directly when searching, which is great.&lt;/p&gt;

&lt;h2&gt;
  
  
  Is it really stateless?
&lt;/h2&gt;

&lt;p&gt;There's an important subtlety to notice here. Our "shared secret" is only shared between Algolia and our company. It's different for every Algolia customer (and even every registered application belonging to the same customer). Most JWT tutorials sign the JWT with a single secret per service, as if every Algolia customer were using the same shared secret. This probably changes the exact understanding of "stateless".&lt;/p&gt;

&lt;p&gt;In the step described as &lt;code&gt;validate(token, app)&lt;/code&gt;, Algolia must look up the shared secret belonging to &lt;code&gt;app&lt;/code&gt;, in order to check that &lt;code&gt;token&lt;/code&gt;'s signature is valid. Depending on how this is implemented, it might require database lookups, etc., but that's for Algolia to optimise. From our perspective when creating tokens, no round-trips to Algolia are required.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>security</category>
      <category>architecture</category>
      <category>learning</category>
    </item>
    <item>
      <title>Destroy All Dependencies, or: why structural typing is awesome</title>
      <dc:creator>Daniel Buckmaster</dc:creator>
      <pubDate>Wed, 02 Dec 2020 10:19:43 +0000</pubDate>
      <link>https://dev.to/crabmusket/destroy-all-dependencies-or-why-typescript-is-awesome-5dj</link>
      <guid>https://dev.to/crabmusket/destroy-all-dependencies-or-why-typescript-is-awesome-5dj</guid>
      <description>&lt;p&gt;When designing software, we strive to ensure each module, class, or function has a &lt;em&gt;single responsibility&lt;/em&gt;. We want to be able to reuse small, focused pieces of code, and we want our tests to be clean and understandable.&lt;/p&gt;

&lt;p&gt;But a piece of software as a whole usually has more than one responsibility! Sindre Sorhus, noted developer of small NPM modules, puts it succinctly &lt;a href="https://github.com/sindresorhus/ama/issues/10#issuecomment-117766328"&gt;in this comment&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You make small focused modules for reusability and to make it possible to build larger more advanced things that are easier to reason about.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Our modules should be small and focused, but the end goal is to &lt;em&gt;integrate&lt;/em&gt; them into a larger whole. This means the modules that make up our applications must have &lt;em&gt;dependencies&lt;/em&gt; between each other; they cannot live in blissful isolation.&lt;/p&gt;

&lt;p&gt;This means that &lt;strong&gt;dependencies are a necessary evil in software development.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Because dependencies are a &lt;strong&gt;necessary evil&lt;/strong&gt;, we try to keep control of them as much as possible. According to Sandi Metz &lt;a href="https://www.poodr.com/"&gt;in her excellent book&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Object-oriented design is about managing dependencies. It is a set of coding techniques that arrange dependencies such that objects can tolerate change ... In the absence of design, unmanaged dependencies wreak havoc because objects know too much about one another.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;While Sandi is talking about &lt;em&gt;object-oriented&lt;/em&gt; design in particular, the principle applies to all ways of designing programs. Carefully managing the dependencies of each module of code you write will lead to cleaner, less-tightly-coupled code that's easier to test and reuse.&lt;/p&gt;

&lt;p&gt;The example in this article will use TypeScript in object-oriented style. We're going to look at a piece of code with some obvious   dependencies and some subtle ones, and then we'll use a few well-known techniques to remove as many of those dependencies as we can. The concepts and tools we'll use are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The single-responsibility principle&lt;/li&gt;
&lt;li&gt;The dependency injection pattern&lt;/li&gt;
&lt;li&gt;Duck typing&lt;/li&gt;
&lt;li&gt;TypeScript's structural typing capabilities&lt;/li&gt;
&lt;li&gt;Generics and the principle of parametricity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After our changes, we'll have made our module much more reusable and more robust to changes in the rest of the application it's part of.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;If you want the TLDR, you can skip to the starting code and the final result&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  A note about static types
&lt;/h3&gt;

&lt;p&gt;Part of the inspiration for writing this article was the idea that dynamically-typed languages have it easier than statically-typed languages when it comes to reusability. Because types don't have to be declared, imported, and pinned down, the code is unencumbered to do what needs to be done now, and to change in the future.&lt;/p&gt;

&lt;p&gt;Type systems have come a long way in the last decade. New statically-typed languages have emerged and gone mainstream. Existing languages have gained new features.&lt;/p&gt;

&lt;p&gt;In this post we'll end up writing code that feels very dynamic, even though it's statically-typed and safe. This is, I think, a real gift of TypeScript's type system, as you'll see.&lt;/p&gt;

&lt;h3&gt;
  
  
  A disclaimer about premature design
&lt;/h3&gt;

&lt;p&gt;Before we dive into the code, I want to point out that it's possible to do &lt;em&gt;too much design&lt;/em&gt; up-front. &lt;a href="https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction"&gt;Premature abstraction&lt;/a&gt;, &lt;a href="https://www.justinweiss.com/articles/i-dry-ed-up-my-code-and-now-its-hard-to-work-with-what-happened/"&gt;code that is too DRY&lt;/a&gt;, and imagining future requirements can all create more problems than they're worth.&lt;/p&gt;

&lt;p&gt;But, that said, it's possible to write code that maintains more flexibility than less, even when all requirements aren't yet known. Different ways of coding the same behaviour can create fewer or more dependencies, without changing the level of DRYness or abstraction.&lt;/p&gt;

&lt;p&gt;The advice in this post has two purposes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;To introduce you to some techniques which result in fewer dependencies, which you can apply &lt;em&gt;habitually&lt;/em&gt; when writing new code.&lt;/li&gt;
&lt;li&gt;To help you learn how to apply these techniques when changing requirements &lt;em&gt;force&lt;/em&gt; you to break apart dependencies.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With that in mind, let's get started.&lt;/p&gt;

&lt;h2&gt;
  
  
  Breadth-first search with lots of dependencies
&lt;/h2&gt;

&lt;p&gt;Take a look at this (incomplete) snippet of TypeScript code which implements &lt;a href="https://yourbasic.org/algorithms/graph/"&gt;breadth-first search on a graph&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Graph&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;./graph&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;breadthFirstSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;startingNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;nodeToFind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;graph&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;Graph&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startingNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pop&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;nodesToVisit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// algorithm omitted for brevity&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;result&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;I've omitted the meat of the BFS algorithm, but you can see the important parts, which are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creating a &lt;code&gt;Graph&lt;/code&gt; from the nodes and edges we're given&lt;/li&gt;
&lt;li&gt;Calling the graph's &lt;code&gt;successor&lt;/code&gt; method, which returns the names of the nodes connected to the given node&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first thing we should do when looking at this code is ask ourselves: what dependencies does this code have? Have a think before reading on.&lt;/p&gt;

&lt;p&gt;There's one obvious dependency: importing the &lt;code&gt;graph.ts&lt;/code&gt; module at the top of the file. However, there are many implicit dependencies in this code, which take a little bit of thought to discern:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What data to pass to the &lt;code&gt;Graph&lt;/code&gt; constructor (nodes and edges)&lt;/li&gt;
&lt;li&gt;Where to find the &lt;code&gt;Graph&lt;/code&gt; constructor (in &lt;code&gt;graph.ts&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;What type of nodes the graph stores (each node is a &lt;code&gt;string&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The names of particular methods the &lt;code&gt;Graph&lt;/code&gt; class has (in this case, just &lt;code&gt;successors&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;How to call those &lt;code&gt;Graph&lt;/code&gt; methods (e.g. &lt;code&gt;successors&lt;/code&gt; takes a single &lt;code&gt;string&lt;/code&gt; and returns an array of them)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You might not be used to thinking of things like class names and method parameter lists as dependencies. But they represent &lt;em&gt;knowledge about external code&lt;/em&gt;, just as much as a hardcoded file location does. These pieces of knowledge tie our code to that external code, and mean that if the external code changes, our code will have to change too.&lt;/p&gt;

&lt;p&gt;Some of these are necessary dependencies, but others are &lt;em&gt;incidental&lt;/em&gt;. Incidental dependencies can be caused by careless design, but can be remedied just as easily. Let's take the first step in reducing our code's dependency on the outside world: reducing the amount of &lt;em&gt;responsibility&lt;/em&gt; it has.&lt;/p&gt;

&lt;h2&gt;
  
  
  The single-responsibility principle
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Single-responsibility_principle"&gt;single responsibility principle&lt;/a&gt;, which is a staple of object-oriented programming but can be applied anywhere, encourages us to write code so that &lt;em&gt;"a class should have only one reason to change."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;What is the &lt;em&gt;responsibility&lt;/em&gt; of our BFS function as it is currently written? If we were to describe it in one sentence, we might say it like this:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;breadthFirstSearch creates a Graph from the given nodes and edges, and searches for a path between two nodes within it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The presence of an &lt;em&gt;and&lt;/em&gt; in that sentence indicates there is more than one responsibility. We need to find a way to remove the first responsibility. We'll find that in removing a responsibility, we also remove dependencies.&lt;/p&gt;

&lt;p&gt;You might think that creating a &lt;code&gt;Graph&lt;/code&gt; object is a mere implementation detail, of the same level of significance as creating the &lt;code&gt;result&lt;/code&gt; array, for example. And you may certainly be right to think that! When looking at a snippet of code like this, outside the context of a wider application, it's hard to say. In every instance, you will need to think through what counts as a responsibility, what is a mere implementation detail, and where to draw the boundaries of your modules. My purpose here is to illustrate what &lt;em&gt;may&lt;/em&gt; be, not to proscribe the optimal way to structure breadth-first search algorithms.&lt;/p&gt;

&lt;p&gt;Let's use the &lt;a href="https://en.wikipedia.org/wiki/Dependency_injection"&gt;dependency injection&lt;/a&gt; pattern to remove the responsibility for creating a graph. To do that, we'll change the code as follows:&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;Graph&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;./graph&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;breadthFirstSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Graph&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;startingNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;nodeToFind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="c1"&gt;// the rest remains unchanged&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We removed the &lt;code&gt;nodes&lt;/code&gt; and &lt;code&gt;edges&lt;/code&gt; arguments, instead accepting a &lt;code&gt;graph&lt;/code&gt; of type &lt;code&gt;Graph&lt;/code&gt;. Instead of creating a dependent object, the function now accepts it as an argument. By doing that, it has refused to take responsibility for &lt;em&gt;creating&lt;/em&gt; the graph, even though it still depends on a graph existing at some point.&lt;/p&gt;

&lt;p&gt;Let's look back at our list of dependencies and see how it's different now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;del&gt;What data to pass to the &lt;code&gt;Graph&lt;/code&gt; constructor&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;That &lt;code&gt;graph&lt;/code&gt; is an instance of the &lt;code&gt;Graph&lt;/code&gt; class&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Where to find the &lt;code&gt;Graph&lt;/code&gt; constructor&lt;/li&gt;
&lt;li&gt;What type of nodes the graph stores (each node is a &lt;code&gt;string&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The names of particular methods the &lt;code&gt;Graph&lt;/code&gt; class has (in this case, just &lt;code&gt;successors&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;How to call those &lt;code&gt;Graph&lt;/code&gt; methods (e.g. &lt;code&gt;successors&lt;/code&gt; takes a single &lt;code&gt;string&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We seem to have introduced a new dependency, in the process of trying to remove one: now our code knows that the &lt;code&gt;graph&lt;/code&gt; parameter is an instance of a class - the &lt;code&gt;Graph&lt;/code&gt; class in particular.&lt;/p&gt;

&lt;p&gt;This is a much smaller dependency. We've traded a large piece of knowledge - how to use the &lt;code&gt;Graph&lt;/code&gt; constructor - for a smaller piece: merely that the &lt;code&gt;Graph&lt;/code&gt; constructor exists.&lt;/p&gt;

&lt;p&gt;But we would still like to remove this dependency entirely, rather than only shrinking it, if we can. And it turns out: we can.&lt;/p&gt;

&lt;h2&gt;
  
  
  Duck typing with interfaces
&lt;/h2&gt;

&lt;p&gt;Let's think for a moment about this new dependency we've introduced. It may be smaller than the original dependency, but it still has some troubling implications.&lt;/p&gt;

&lt;p&gt;In a statically-typed language, declaring that &lt;code&gt;graph&lt;/code&gt; has type &lt;code&gt;Graph&lt;/code&gt; (where &lt;code&gt;Graph&lt;/code&gt; is a class constructor) means that we can never pass anything into this parameter which is not an instance of the &lt;code&gt;Graph&lt;/code&gt; class or one of its subclasses.&lt;/p&gt;

&lt;p&gt;This might seem reasonable, but it does reduce the flexibility of our code. Object-oriented inheritance can be useful, but we shouldn't force it on users of our code without good reason to. Languages like C++ have typically used inheritance heavily to enable polymorphism, because they do not have alternatives. But in TypeScript, as in many modern object-oriented languages, we can do better.&lt;/p&gt;

&lt;p&gt;We can apply a principle known as &lt;a href="https://en.wikipedia.org/wiki/Duck_typing"&gt;duck typing&lt;/a&gt; to remove the implicit dependency on the class hierarchy here. Instead of depending on a &lt;em&gt;specific class constructor&lt;/em&gt;, we'll depend on an &lt;em&gt;interface&lt;/em&gt;. The difference is that interfaces are not tied to any specific class hierarchy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In duck typing, an object's suitability is determined by the presence of certain methods and properties, rather than the type of the object itself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's create a new file called &lt;code&gt;graph_interface.ts&lt;/code&gt; to help with this. We'll declare all the capabilities of graphs which our application needs in one location:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;graph_interface.ts&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="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;GraphInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;predecessors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&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;// ... other graph methods&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we'll modify our BFS module like so:&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;GraphInterface&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;./graph_interface&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;breadthFirstSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GraphInterface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;startingNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;nodeToFind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&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;// the rest remains unchanged&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, instead of depending on the &lt;code&gt;Graph&lt;/code&gt; class itself, we depend on the new interface. Any type can implement this interface, regardless of a class's lineage. For example, we might end up creating new graph types that look like some of these:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This class of graph has no parent class&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;SparseGraph&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;GraphInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// This class is the child of a class from the JavaScript standard library&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AdjacencyMatrix&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Uint8Array&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;GraphInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// This class is a child of our original Graph class&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;DirectedGraph&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Graph&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;GraphInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have strictly increased the reusability of our code, because any type can stick to the interface our code needs. This is an example of the &lt;a href="https://en.wikipedia.org/wiki/Duck_typing"&gt;duck typing&lt;/a&gt; pattern:&lt;/p&gt;

&lt;p&gt;Let's do another check of our dependency list:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;del&gt;That &lt;code&gt;graph&lt;/code&gt; is an instance of the &lt;code&gt;Graph&lt;/code&gt; class&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;That &lt;code&gt;graph&lt;/code&gt; conforms to the &lt;code&gt;GraphInterface&lt;/code&gt; type&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Where to find the &lt;code&gt;GraphInterface&lt;/code&gt; type&lt;/li&gt;
&lt;li&gt;What type of nodes the graph stores (each node is a &lt;code&gt;string&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The names of particular methods the &lt;code&gt;GraphInterface&lt;/code&gt; type has (in this case, just &lt;code&gt;successors&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;How to call those &lt;code&gt;GraphInterface&lt;/code&gt; methods (e.g. &lt;code&gt;successors&lt;/code&gt; takes a single &lt;code&gt;string&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We've removed the &lt;code&gt;Graph&lt;/code&gt; class dependency for good, and have modified the following dependencies to refer now to &lt;code&gt;GraphInterface&lt;/code&gt; instead of &lt;code&gt;Graph&lt;/code&gt;, but we've again introduced a new one dependency! (Will this nightmare ever end? Are we making progress, or just painting over the cracks in our shoddy design?)&lt;/p&gt;

&lt;p&gt;As with the previous change we made, we've swapped a larger piece of knowledge for a smaller piece. The &lt;code&gt;Graph&lt;/code&gt; class implied an inheritance hierarchy, but the &lt;code&gt;GraphInterface&lt;/code&gt; does not. While numerically our dependencies have stayed the same, we've reduced the amount of knowledge they contain. This makes them more manageable.&lt;/p&gt;

&lt;p&gt;But now, thanks to an important feature of TypeScript's type system, and the changes we've made up to this point, we can make a dramatic improvement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Duck typing &lt;em&gt;with structural types&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;Astute readers will have noticed that in the last section, I gave some examples of classes that looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;DirectedGraph&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Graph&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;GraphInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But in TypeScript, unlike most statically-typed languages, it's not necessary to declare &lt;code&gt;implements GraphInterface&lt;/code&gt;. As long as a class is compatible with an interface &lt;em&gt;at the point of use&lt;/em&gt;, TypeScript will be happy! We don't need to declare compatibility ahead of time.&lt;/p&gt;

&lt;p&gt;This is known as &lt;em&gt;structural typing&lt;/em&gt;. It's an extremely useful feature which we will now make use of. Structural typing contrasts to &lt;em&gt;nominative typing&lt;/em&gt;, where the specific identity of each type is unique and significant. &lt;a href="http://wiki.c2.com/?NominativeAndStructuralTyping"&gt;Read more about structural and nominative typing.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Because of structural typing, we don't have to depend on a shared interface defined elsewhere. Let's move the interface declaration right into our module, like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;GraphInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;predecessors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;nodes&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;edges&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;string&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;// ... other graph methods&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;breadthFirstSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GraphInterface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;startingNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;nodeToFind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&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;// ...&lt;/span&gt;

  &lt;span class="k"&gt;while&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;nodesToVisit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&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 don't import &lt;code&gt;GraphInterface&lt;/code&gt;, but declare it &lt;em&gt;where it's needed&lt;/em&gt;. This is an important ability in languages like TypeScript and Go.&lt;/p&gt;

&lt;p&gt;Here, we can cross a dependency off our list and, thankfully, not introduce any new ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;That &lt;code&gt;graph&lt;/code&gt; conforms to the &lt;code&gt;GraphInterface&lt;/code&gt; type&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Where to find the &lt;code&gt;GraphInterface&lt;/code&gt; type&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;What type of nodes the graph stores (each node is a &lt;code&gt;string&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The names of particular methods the &lt;code&gt;GraphInterface&lt;/code&gt; type has (in this case, just &lt;code&gt;successors&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;How to call those &lt;code&gt;GraphInterface&lt;/code&gt; methods (e.g. &lt;code&gt;successors&lt;/code&gt; takes a single &lt;code&gt;string&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We no longer depend on the interface being found anywhere except &lt;em&gt;right here&lt;/em&gt; where it's used. We could rename every other file in our application, and this module would not even notice.&lt;/p&gt;

&lt;p&gt;This is another big step forwards, but you might be getting a niggling feeling that something is wrong when looking at the code above. Let's take a moment to address that niggle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Increasing flexibility using the interface segregation principle
&lt;/h2&gt;

&lt;p&gt;The niggle is probably coming from the fact that our newly-moved &lt;code&gt;GraphInterface&lt;/code&gt; declares a bunch of methods that &lt;code&gt;breadthFirstSearch&lt;/code&gt; &lt;em&gt;doesn't use&lt;/em&gt;. For example, &lt;code&gt;predecessors&lt;/code&gt; is never used.&lt;/p&gt;

&lt;p&gt;This is a violation of the &lt;a href="https://en.wikipedia.org/wiki/Interface_segregation_principle"&gt;interface segregation principle&lt;/a&gt;, which suggests that &lt;em&gt;"no client should be forced to depend on methods it does not use."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This phrasing (from the Wikipedia page) is not a precise fit for our code example, but the principle definitely applies. Fortunately, we can easily remedy this, and in doing so increase the flexibility of our module.&lt;/p&gt;

&lt;p&gt;Let's revise the &lt;code&gt;GraphInterface&lt;/code&gt; like so:&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;GraphInterface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;breadthFirstSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;GraphInterface&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;startingNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;nodeToFind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&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;// ...&lt;/span&gt;

  &lt;span class="k"&gt;while&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;nodesToVisit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="c1"&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 the interface has shrunk to include &lt;em&gt;precisely&lt;/em&gt; the functionality we need from it, it doesn't represent the entire concept of "graphness" any more, and we should probably rename it. (Luckily, this is safe to do, because the interface is not exported, so no external code could be depending on it!)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;BreadthFirstSearchable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;breadthFirstSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BreadthFirstSearchable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="c1"&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 interface is now acting as a declaration of the types of things that can be searched with our &lt;code&gt;breadthFirstSearch&lt;/code&gt; function. For more exploration of this pattern, have a read of &lt;a href="https://www.cl.cam.ac.uk/teaching/1516/L28/parametricity.pdf"&gt;this great blog post&lt;/a&gt; which uses examples in Go, another structurally-typed language.&lt;/p&gt;

&lt;p&gt;Let's take another look at our list of dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;del&gt;That &lt;code&gt;graph&lt;/code&gt; conforms to the &lt;code&gt;BreadthFirstSearchable&lt;/code&gt; type&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;What type of nodes the graph stores (each node is a &lt;code&gt;string&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The names of particular methods the &lt;code&gt;graph&lt;/code&gt; object has (in this case, just &lt;code&gt;successors&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;How to call those methods (e.g. &lt;code&gt;successors&lt;/code&gt; takes a single &lt;code&gt;string&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I have modified the final two dependencies slightly, and in doing so, have made the first dependency redundant. Because our &lt;code&gt;BreadthFirstSearchable&lt;/code&gt; interface perfectly fits just the methods our code actually uses, the interface itself is insignificant; it's merely a convenient syntax to declare how we will use the &lt;code&gt;graph&lt;/code&gt; object.&lt;/p&gt;

&lt;h2&gt;
  
  
  Take a breather
&lt;/h2&gt;

&lt;p&gt;We've done extremely well so far, reducing our list of five weighty dependencies to three. Take a second to congratulate yourself!&lt;/p&gt;

&lt;p&gt;If we stopped here, we could be proud of our work. We've successfully&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;excised a responsibility that our module shouldn't have had in the first place,&lt;/li&gt;
&lt;li&gt;removed an import of an external file,&lt;/li&gt;
&lt;li&gt;abolished the implicit dependency on a class hierarchy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;and in doing so, have made the code clearer and more focused. A side-effect of declaring interfaces &lt;em&gt;at the point of use&lt;/em&gt; is to have explicit documentation about what our breadth-first search module really &lt;em&gt;needs&lt;/em&gt; in order to work.&lt;/p&gt;

&lt;p&gt;Notice that the remaining dependencies seem much more difficult to consider removing. After all, how could we make a BFS algorithm that doesn't depend on knowing the name of the &lt;code&gt;successors&lt;/code&gt; method? Could we take this too far?&lt;/p&gt;

&lt;p&gt;Of the dependencies that remain, I would argue the final two are very reasonable dependencies to keep. They express the core meaning of the code. Breadth-first search depends on searching the &lt;em&gt;successors&lt;/em&gt; of nodes in a graph. Each node may have zero, one, or many successors. These are fundamental facts about graph theory that we can't really get around. So it's unlikely we'll be able to remove these dependencies, no matter how clever we are.&lt;/p&gt;

&lt;p&gt;However, the dependency on the &lt;code&gt;string&lt;/code&gt; type can be dispensed of. If you want to try the Full Monty, read on to find out how.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using generics to reduce knowledge
&lt;/h2&gt;

&lt;p&gt;Our code currently knows that each node in the &lt;code&gt;graph&lt;/code&gt; is a &lt;code&gt;string&lt;/code&gt;. This looks like a single piece of knowledge. But, like the &lt;code&gt;Graph&lt;/code&gt; class implies an inheritance hierarchy, the &lt;code&gt;string&lt;/code&gt; type implies other knowledge:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Nodes can be compared using not just &lt;code&gt;==&lt;/code&gt; and &lt;code&gt;===&lt;/code&gt;, but &lt;code&gt;&amp;lt;&lt;/code&gt;, &lt;code&gt;&amp;gt;&lt;/code&gt;, &lt;code&gt;localeCompare&lt;/code&gt;, etc.&lt;/li&gt;
&lt;li&gt;We can ask each node for its &lt;code&gt;.length&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;We can call &lt;code&gt;node.substring&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Etcetera...&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Built-in types like &lt;code&gt;string&lt;/code&gt; usually bring a lot of knowledge with them, because they are designed to be feature-ful! Usually it's not a problem to rely on this knowledge. Built-in types change so infrequently (especially not in breaking ways) that it's very safe to leave these dependencies in your code.&lt;/p&gt;

&lt;p&gt;However, knowledge of concrete types can sometimes reduce flexibility and reusability. An immediate example that comes to mind is that some graphs might have numeric identifiers instead of string-based identifiers.&lt;/p&gt;

&lt;p&gt;Bearing in mind my advice at the beginning about not doing too much &lt;em&gt;premature design&lt;/em&gt; and not &lt;em&gt;anticipating requirements&lt;/em&gt;, let's explore the way we can use generic types to make this code more flexible &lt;em&gt;if appropriate&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;First, let's make an alias of the &lt;code&gt;string&lt;/code&gt; type, for clarity:&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;type&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;BreadthFirstSearchable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;breadthFirstSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BreadthFirstSearchable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;startingNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;nodeToFind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startingNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pop&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;nodesToVisit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's now easier to see where we must insert type parameters in order to remove the knowledge of the specific type. After removing the alias &lt;code&gt;type Node&lt;/code&gt; and adding generic parameters, the code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;BreadthFirstSearchable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;breadthFirstSearch&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BreadthFirstSearchable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;startingNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;nodeToFind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&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;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We've successfully crossed off a piece of knowledge, and have made our code more flexible in the process. This is what our knowledge list looks like now:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;del&gt;What type of nodes the graph stores (each node is a &lt;code&gt;string&lt;/code&gt;)&lt;/del&gt;&lt;/li&gt;
&lt;li&gt;The names of particular methods the &lt;code&gt;graph&lt;/code&gt; object has (in this case, just &lt;code&gt;successors&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;How to call those methods (e.g. &lt;code&gt;successors&lt;/code&gt; takes a single &lt;code&gt;Node&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Parametricity is a cloud of unknowing
&lt;/h2&gt;

&lt;p&gt;There's an esoteric concept known as &lt;em&gt;parametricity&lt;/em&gt; which is typically talked about in functional programming. This &lt;a href="https://www.cl.cam.ac.uk/teaching/1516/L28/parametricity.pdf"&gt;article from Cambridge (PDF)&lt;/a&gt; puts it thus (with added emphasis):&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Parametricity can be thought of as the dual to abstraction. Where abstraction hides details about an implementation from the outside world, parametricity &lt;strong&gt;hides details about the outside world&lt;/strong&gt; from an implementation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The use of a type parameter means our function &lt;em&gt;knows less&lt;/em&gt; about the outside world, which is what we wanted. This has interesting implications.&lt;/p&gt;

&lt;p&gt;Our code now can't use methods of the String class like &lt;code&gt;substring&lt;/code&gt;, because &lt;code&gt;Node&lt;/code&gt; could mean any type, depending on the caller of our code.&lt;/p&gt;

&lt;p&gt;As described handily in &lt;a href="https://medium.com/bigpanda-engineering/understanding-parametricity-in-scala-520f9f10679a"&gt;this article&lt;/a&gt; using Scala for examples, this lack of knowledge limits the choices we can make when implementing code. We can no longer accidentally use &lt;code&gt;node.length&lt;/code&gt; or any other specific methods or properties. We are prevented from peering beyond the &lt;em&gt;cloud of unknowing&lt;/em&gt; created by the generic type parameter.&lt;/p&gt;

&lt;p&gt;(Of course, because JavaScript has reflection, we can determine information about values with unknown types at runtime. However, &lt;code&gt;typeof&lt;/code&gt; and &lt;code&gt;instanceof&lt;/code&gt; are more likely to be asked about in code review than an innocuous &lt;code&gt;node.length&lt;/code&gt;.)&lt;/p&gt;

&lt;p&gt;But, significantly, the caller now also knows that our code is operating inside this &lt;em&gt;cloud of unknowing&lt;/em&gt;. The caller knows that our code &lt;em&gt;cannot&lt;/em&gt; rely on &lt;code&gt;Node&lt;/code&gt; being any specific type. This gives the caller more freedom and flexibility.&lt;/p&gt;

&lt;h2&gt;
  
  
  Recapping our journey
&lt;/h2&gt;

&lt;p&gt;Here's the code we've ended up with:&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;BreadthFirstSearchable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;node&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;breadthFirstSearch&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BreadthFirstSearchable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;startingNode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;nodeToFind&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Node&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;visited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="na"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;startingNode&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

  &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;queue&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="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;node&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;queue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pop&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;nodesToVisit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;graph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;successors&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// the rest of the algorithm&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;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And here is our list of knowledge that this code has about external code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The names of particular methods the &lt;code&gt;graph&lt;/code&gt; object has (in this case, just &lt;code&gt;successors&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;How to call those methods (e.g. &lt;code&gt;successors&lt;/code&gt; takes a single &lt;code&gt;Node&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We've come a long way, and reduced our knowledge to the very minimum. The remaining dependencies reflect the &lt;em&gt;core abstractions&lt;/em&gt; of our domain. This module should last unchanged for a long time, serenely weathering changes in the code surrounding it, without demanding to be changed in lockstep.&lt;/p&gt;

&lt;p&gt;While it might seem like we might have looked into the future to imagine requirements this code might be fulfilling (e.g. new graph classes, or graphs with numeric nodes), the changes we've made were low-impact and broadly applicable to many situations. We didn't add new features, or introduce new abstractions: we systematically &lt;em&gt;removed knowledge&lt;/em&gt; from the code, and in doing so made it less dependent on the code around it, and more reusable in unexpected future contexts.&lt;/p&gt;

&lt;p&gt;I hope that next time you're writing new code, or refactoring a tangled web of dependencies, these techniques and ways of understanding dependency will help you cut through the chaos and discover clean, single-responsibility modules.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>oop</category>
      <category>codequality</category>
    </item>
    <item>
      <title>JavaScript's ecosystem is uniquely paranoid</title>
      <dc:creator>Daniel Buckmaster</dc:creator>
      <pubDate>Sun, 26 Apr 2020 04:22:47 +0000</pubDate>
      <link>https://dev.to/crabmusket/javascript-s-ecosystem-is-uniquely-paranoid-2dgj</link>
      <guid>https://dev.to/crabmusket/javascript-s-ecosystem-is-uniquely-paranoid-2dgj</guid>
      <description>&lt;p&gt;Another week, another &lt;a href="https://github.com/then/is-promise/issues/13"&gt;NPM-related snafu&lt;/a&gt;. Why does this keep happening to the JavaScript ecosystem? The answer is paranoia. 😱&lt;/p&gt;




&lt;p&gt;Many are quick to assert that JavaScript just has a too-low barrier to entry and the n00bs are messing it up. Whenever anyone says "JavaScript is the new PHP!" this is probably what they mean. I don't feel the need to provide evidence against this claim; I think it comes from an understandable frustration, expressed through all-too-common tech elitism.&lt;/p&gt;

&lt;p&gt;Others say we should blame resume-driven-development, and the ego boost of having published thousands of open-source modules. We must all suffer, the argument goes, because a few obsessive individuals want to be able to boast about how critical &lt;em&gt;they personally&lt;/em&gt; are to the JavaScript ecosystem. While this is probably a real trend, why isn't it more prevalent in other open-source ecosystems?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer before proceeding&lt;/strong&gt;: I use JS every day, and I actually really like it. I'm not trying to criticise it, just to explore some unique problems it has. I hope this post doesn't come across as too harsh.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are probably &lt;em&gt;many&lt;/em&gt; contributing factors that have shaped NPM into what it is today. However, I assert that the &lt;em&gt;underlying&lt;/em&gt; reason for the bizarre profusion of tiny, absurd-seeming one-liner packages on NPM is &lt;strong&gt;paranoia&lt;/strong&gt;, caused by a &lt;em&gt;unique combination&lt;/em&gt; of factors.&lt;/p&gt;

&lt;h2&gt;
  
  
  JavaScript makes you paranoid
&lt;/h2&gt;

&lt;p&gt;Three factors have caused a widespread cultural paranoia among JavaScript developers. This has been inculcated over years. These factors are: JavaScript's weak dynamic type system; the diversity of runtimes JavaScript targets; and the fact of deploying software on the web.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Weak dynamic typing
&lt;/h3&gt;

&lt;p&gt;It's well-known that JavaScript's "type system" leaves a lot to be desired. &lt;a href="https://www.destroyallsoftware.com/talks/wat"&gt;This well-known talk&lt;/a&gt; is a humourous take on some of the many ways you can shoot yourself in the foot in JavaScript.&lt;/p&gt;

&lt;p&gt;Unless your team (and every open-source package your team depends on) always uses &lt;code&gt;===&lt;/code&gt;, knows &lt;em&gt;exactly&lt;/em&gt; when &lt;code&gt;typeof&lt;/code&gt; is acceptable, is good at defensive programming, and designs APIs that have good type discipline*, you've probably been tripped up by a string that behaved like a number, a 0 that was skipped for being falsy, an &lt;code&gt;undefined&lt;/code&gt; turning up somewhere surprising, &lt;code&gt;typeof null === 'object'&lt;/code&gt;, etcetera.&lt;/p&gt;

&lt;p&gt;This isn't &lt;em&gt;entirely&lt;/em&gt; unique to JavaScript - many languages have dynamic types, and many languages have weak types and implicit coercions. But I would argue JavaScript is quite a dire example. And this is still an important contributing factor, without which the second factor probably wouldn't be as significant.&lt;/p&gt;

&lt;p&gt;*Or, you are TypeScript users. See Appendix 3.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Browser runtimes
&lt;/h3&gt;

&lt;p&gt;It's not just the case that "JavaScript is missing a standard library". For example, there is a really easy and straightforward "standard" way to check if an object is an array: &lt;code&gt;thing instanceof Array&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But wait! Enter the &lt;code&gt;iframe&lt;/code&gt;! If the array came from a different context, this check will fail, because the &lt;code&gt;iframe&lt;/code&gt;'s &lt;code&gt;Array&lt;/code&gt; constructor is a different object from the parent window's &lt;code&gt;Array&lt;/code&gt;. Do you &lt;em&gt;really&lt;/em&gt; know where that value came from?&lt;/p&gt;

&lt;p&gt;Enter &lt;code&gt;Array.isArray&lt;/code&gt; to save the day! But wait! What if your code needs to run in an older browser which doesn't support &lt;code&gt;isArray&lt;/code&gt;? Is your transpilation+polyfill pipeline reliable enough to handle this? What do you &lt;em&gt;mean&lt;/em&gt; you're not using &lt;code&gt;babel-env-preset&lt;/code&gt; or whatever the package is called now? This is the downfall of many a well-intentioned addition to JavaScript's standard library (like &lt;code&gt;String.padStart&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Having to deal with an extreme diversity of runtimes seems unique to JavaScript among mainstream languages. This could be my bias showing (I'm primarily a web developer), but it's certainly true of the difference between web frontend code and web backend code. You just &lt;em&gt;never know&lt;/em&gt; where your code is going to run - in Internet Explorer 8, on Opera for Android, or someone's old version of Safari on their iPhone 5 they're clinging to because it would be too expensive to upgrade.&lt;/p&gt;

&lt;p&gt;This is bad enough for application developers, who can to &lt;em&gt;some&lt;/em&gt; extent draw a line and decide &lt;em&gt;not&lt;/em&gt; to support users in certain demographics. (Or, in Kogan's case, &lt;a href="https://www.kogan.com/au/blog/new-internet-explorer-7-tax/"&gt;charge those users more&lt;/a&gt;.) But it's a nightmare for library developers, who want to make their code usable by as many &lt;em&gt;other developers&lt;/em&gt; as possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Bundle size
&lt;/h3&gt;

&lt;p&gt;Do you remember a few months ago when the internet joined in a collective hate-on for the &lt;code&gt;is-buffer&lt;/code&gt; package? This package, as its name suggests, checks whether something is a Buffer.&lt;/p&gt;

&lt;p&gt;Why would one need a package for that? Well, weak typing might make one want to check types like this; moving targets in the runtime might make one worry that one doesn't know &lt;em&gt;how&lt;/em&gt; to check the type reliably - but still, why doesn't one just depend on the buffer package?&lt;/p&gt;

&lt;p&gt;Enter the final triumvir of this unholy alliance: &lt;em&gt;bundle size paranoia&lt;/em&gt;, which was ostensibly &lt;a href="https://github.com/feross/is-buffer/blob/e5a3b31419315bf954f9a7fab2d0d2fceb818f21/README.md#why-not-use-bufferisbuffer"&gt;the reason&lt;/a&gt; the &lt;code&gt;is-buffer&lt;/code&gt; package was created. Because JavaScript programs have to be downloaded &lt;em&gt;frequently&lt;/em&gt; by users (even multiple times by the same user on the same day, if caching isn't used carefully), and because Google has convinced us that milliseconds of additional page load time will have &lt;em&gt;dire&lt;/em&gt; consequences for our users and consequently for our bank accounts, &lt;em&gt;and because&lt;/em&gt; bundlers and module systems have not provided adequate support for modularity, we web developers go to &lt;em&gt;extreme lengths&lt;/em&gt; to avoid shipping unnecessary bytes to our users.&lt;/p&gt;

&lt;p&gt;When the unit of modularity is "NPM package", rather than "file" or even "function", some will go to great lengths to &lt;a href="https://www.npmjs.com/search?q=keywords:lodash-modularized"&gt;split their code across NPM packages&lt;/a&gt;. (For more on this, see Appendix 1.) This works with old bundlers that can't tree-shake, and it &lt;em&gt;can&lt;/em&gt; avoid reuse - though as noted by the &lt;a href="https://lodash.com/per-method-packages"&gt;lodash project itself&lt;/a&gt;, they are thankfully moving away from this pattern because it may introduce more opportunities to &lt;em&gt;duplicate&lt;/em&gt; code than to &lt;em&gt;deduplicate&lt;/em&gt; it!&lt;/p&gt;

&lt;p&gt;A huge amount of effort has been poured into not just minifying a source bundle, but producing the best possible bundle in the first place. The NPM ecosystem as it stands today has been shaped in part by these efforts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Future proof
&lt;/h2&gt;

&lt;p&gt;These three factors combine and interact in unexpected and awful ways.&lt;/p&gt;

&lt;p&gt;Over the years there has been rapid evolution in both frontend frameworks and backend JavaScript, high turnover in bundlers and best-practises. This has metastasized into a culture of uncertainty, an air of paranoia, and an extreme profusion of small packages. Reinventing the wheel can sometimes be good - but would you really bother doing it if you had to learn all the arcane bullshit of browser evolution, IE8 compatibility, implementation bugs, etc. &lt;em&gt;ad infinitum&lt;/em&gt;?&lt;/p&gt;

&lt;p&gt;And it's not just that you don't understand how things work &lt;em&gt;now&lt;/em&gt;, or how they &lt;em&gt;used&lt;/em&gt; to work - but that they'll change in the future!&lt;/p&gt;

&lt;p&gt;Whenever NPM's package culture is discussed, one of the benefits touted is that if one of your dependencies is ever updated, your own code will now be updated "for free"! Your application will remain correct, because it depends on an abstraction that will remain correct. (Abstractions are good, but see Appendix 2.)&lt;/p&gt;

&lt;p&gt;This is a very reasonable expectation, and an important piece of progress in software development. But I believe the paranoia created by the three factors I discussed above have led to the excesses we see in the current NPM ecosystem. This is why we have &lt;a href="https://www.npmjs.com/package/is-even"&gt;is-even&lt;/a&gt; and its whole ludicrous web of dependencies, and why we don't have &lt;code&gt;is-even&lt;/code&gt; in Python.&lt;/p&gt;

&lt;p&gt;"Surely," the rational developer exclaims, "there could be no future changes to the &lt;code&gt;is-even&lt;/code&gt; package. The definition of even numbers isn't going to change any time soon!"&lt;/p&gt;

&lt;p&gt;No, the definition of even numbers won't ever change. But sadly, my friend, this is JavaScript - and you can &lt;em&gt;never really be sure.&lt;/em&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Appendix 1. In praise of modules
&lt;/h3&gt;

&lt;p&gt;My thoughts on this issue have been brewing for a while, but &lt;a href="https://github.com/sindresorhus/ama/issues/10#issuecomment-117766328"&gt;this comment by Sindre Sorhus&lt;/a&gt;, noted small-package developer, really put it all in focus for me.&lt;/p&gt;

&lt;p&gt;Sindre makes a very good argument in favour of modules:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;tl;dr You make small focused modules for reusability and to make it possible to build larger more advanced things that are easier to reason about.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;However, this is not an argument in favour of &lt;em&gt;NPM packages&lt;/em&gt;. All the benefits Sindre lists could be achieved by simply designing programs in a modular way. If another developer wants to avoid having to re-implement an interesting but not-entirely-trivial piece of functionality, they should be able to lift a well-defined module (ideally a &lt;a href="https://github.com/kazzkiq/darkmode/blob/2312fdcf4ac49721a6ec0e4727106ba8d2e485f7/src/index.ts"&gt;single file&lt;/a&gt;) from one project to another.&lt;/p&gt;

&lt;p&gt;A lot of the issues with NPM are caused by... well, NPM, not by some inherent property of small modules. This was the case for last week's &lt;code&gt;is-promise&lt;/code&gt; debacle (which precipitated me actually writing this blog post).  &lt;em&gt;Small NPM packages&lt;/em&gt; are the "problem", not small modules, and the problem, at its root, is caused by paranoia.&lt;/p&gt;

&lt;h3&gt;
  
  
  Appendix 2. The meaning of abstractions
&lt;/h3&gt;

&lt;p&gt;What's wrong with this code?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isPromise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;is-promise&lt;/span&gt;&lt;span class="dl"&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;isPromise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;thing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;successCallback&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;failureCallback&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(It's from a real application that uses &lt;code&gt;is-promise&lt;/code&gt;, but I won't name names.)&lt;/p&gt;

&lt;p&gt;Did you spot it? &lt;code&gt;catch&lt;/code&gt; might be undefined. Why? &lt;code&gt;is-promise&lt;/code&gt; implements the &lt;a href="https://promisesaplus.com/"&gt;Promises/A+ spec&lt;/a&gt;, which only requires a &lt;code&gt;then&lt;/code&gt; method. The specific meaning of "is &lt;code&gt;thing&lt;/code&gt; a promise?" can actually change based on &lt;em&gt;how you want to use the answer&lt;/em&gt;. The "promise" is not a reliable abstraction here, because JavaScript has so many versions of it, and because promises can be used in many ways.&lt;/p&gt;

&lt;p&gt;This is slightly tangential to the paranoia discussed above, but is an outcome of a "don't ask" approach to packages ("don't ask" because the details will horrify you), and probably not unique to JavaScript.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;UPDATE:&lt;/strong&gt; apparently even the package maintainer &lt;a href="https://github.com/then/is-promise/pull/40"&gt;failed to notice the distinction&lt;/a&gt; between a &lt;code&gt;Promise&lt;/code&gt; and something that has a &lt;code&gt;then&lt;/code&gt; method. This stuff is not trivial.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The pattern of doing this kind of typecheck is all-too-prevalent in the JS ecosystem, which privileges APIs that seem "simple" because you can chuck anything you want into them, but pushes the burden of being compatible with every conceivable input onto the library. Which brings me to my next appendix...&lt;/p&gt;

&lt;h3&gt;
  
  
  Appendix 3. TypeScript
&lt;/h3&gt;

&lt;p&gt;Is there a solution to all this? How can we stop the madness?&lt;/p&gt;

&lt;p&gt;I don't believe TypeScript is a &lt;em&gt;solution&lt;/em&gt;. If anything, it's a clear &lt;em&gt;symptom&lt;/em&gt; of the problem. But I believe that TypeScript helps do something important: &lt;em&gt;it makes poorly-typed code annoying to write&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Yes, you &lt;a href="https://www.typescriptlang.org/docs/handbook/functions.html#overloads"&gt;can design&lt;/a&gt; a method that accepts anything from a &lt;code&gt;string&lt;/code&gt; to a &lt;code&gt;then&lt;/code&gt;able that will return an object containing a &lt;code&gt;Float64Array&lt;/code&gt;, but writing the type of that method becomes &lt;em&gt;ugly&lt;/em&gt;, and implementing it becomes a &lt;em&gt;pain&lt;/em&gt; because TypeScript forces you to demonstrate to its satisfaction that you've done it correctly.&lt;/p&gt;

&lt;p&gt;Fewer APIs that take and return different types make it less necessary to implement code like &lt;code&gt;is-buffer&lt;/code&gt;, &lt;code&gt;is-number&lt;/code&gt;, etcetera. Of course, browser compatiblity and bundle size anxiety will still present problems. But maybe with an increase in JavaScript developers designing code with types, we'll see less demand for typecheck packages and the like.&lt;/p&gt;

&lt;h3&gt;
  
  
  Appendix 4. Deno
&lt;/h3&gt;

&lt;p&gt;One of the reasons I'm excited for &lt;a href="https://deno.land"&gt;Deno&lt;/a&gt;'s upcoming stable release is that it builds on a philosophy of &lt;em&gt;fewer, better dependencies&lt;/em&gt;. But even in cases where you need a specific dependency, Deno's URL-based imports make it trivial to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Import &lt;em&gt;just a single file&lt;/em&gt; without downloading a whole package plus its tests and everything else. Refer back to Appendix 1 for why this is cool.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Pin each import &lt;em&gt;to a commit hash&lt;/em&gt; or other stable identifier.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Yes, many people are concerned about the idea of importing URLs for many legitimate reasons. NPM is a more trusted place to host packages than some random website. But not even NPM can be 100% reliable indefinitely. Deno at least makes you stop and think... &lt;em&gt;do I trust this source?&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>npm</category>
      <category>opinion</category>
    </item>
  </channel>
</rss>
