<?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: Reinis Ivanovs</title>
    <description>The latest articles on DEV Community by Reinis Ivanovs (@slikts).</description>
    <link>https://dev.to/slikts</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%2F94092%2Fb02ccf4d-80ed-49ad-8edf-502d25f12ac3.png</url>
      <title>DEV Community: Reinis Ivanovs</title>
      <link>https://dev.to/slikts</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/slikts"/>
    <language>en</language>
    <item>
      <title>Extending native JS prototypes is not such a crazy idea with symbols</title>
      <dc:creator>Reinis Ivanovs</dc:creator>
      <pubDate>Thu, 20 Jul 2023 15:37:23 +0000</pubDate>
      <link>https://dev.to/slikts/extending-native-js-prototypes-is-not-such-a-crazy-idea-with-symbols-2h8l</link>
      <guid>https://dev.to/slikts/extending-native-js-prototypes-is-not-such-a-crazy-idea-with-symbols-2h8l</guid>
      <description>&lt;p&gt;Dynamic languages like JavaScript have something called "open classes" that allow to extend or monkey patch code at runtime, including the standard built-in objects, and this has always tempted users to try and improve the language with custom methods that are in the shared global namespaces like &lt;code&gt;Array.prototype&lt;/code&gt; instead of their own, because it's just convenient that objects come "batteries included" without having to be wrapped in anything and even if they're constructed using literal syntax. To illustrate, you could look at all the historical Stack Overflow answers about flattening arrays before &lt;code&gt;Array.prototype.flat()&lt;/code&gt; was added in 2019, because all of them come with different tradeoffs for something that should be a very basic language feature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workaround #1 for missing built-in methods: helpers 🛠️
&lt;/h2&gt;

&lt;p&gt;It's no big deal, right? Just abstract flattening to a helper function:&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;function&lt;/span&gt; &lt;span class="nx"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[].&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;([],&lt;/span&gt; &lt;span class="nx"&gt;arr&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;Except this comes with a host of practical, performance and aesthetic issues, starting from the fact that it's not chainable like other array methods and you need intermediate variables, which you can fix by making it a callback to &lt;code&gt;.reduce()&lt;/code&gt;, but then it's making &lt;code&gt;N&lt;/code&gt; function calls instead of just one like before, etc. It's still no big deal, but the inconvenience adds up, including if you're using helper libraries like Lodash where a lot of work has already been done for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workaround #2: wrappers 🎁
&lt;/h2&gt;

&lt;p&gt;Wrappers step up the complexity, but improve on just helper functions because they allow method chaining, with the most classic one being jQuery's &lt;code&gt;$()&lt;/code&gt;. The nice thing about wrappers is that they can namespace methods and editors can show context-aware autocompletion for them, but their Achilles heel is the need to wrap and especially unwrap values, and also that wrapping or converting hides the previous identity so you can't do simple identity comparisons etc. All in all, the fact that even high-profile projects like &lt;code&gt;Immutable.js&lt;/code&gt; have limited adoption testify to wrappers just not being convenient enough.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workaround #3: function composition and pipelining 🪠
&lt;/h2&gt;

&lt;p&gt;An alternative to method chaining or the so-called fluent interfaces is pipelining, and, for example, Lodash provides it as &lt;code&gt;_.pipeline()&lt;/code&gt;. This is the functional approach, and functional languages have built-in support for it, but even though JavaScript is a multi-paradigm language and has functional elements, pipelining is just not idiomatic in JavaScript, while chaining is. This is illustrated by the difficulties the &lt;a href="https://github.com/tc39/proposal-pipeline-operator"&gt;pipeline operator proposal&lt;/a&gt; has faced in getting standardized, even though it's on many developer's wish list.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workaround #4: native prototype extension 🏗️
&lt;/h2&gt;

&lt;p&gt;This circles back to the beginning of the article with array flattening as a missing standard feature, because around 2006, when the first JavaScript libraries were just appearing, one of them went and fixed this issue by implementing their own &lt;code&gt;Array.prototype.flatten&lt;/code&gt;, and it also tried to "play nice" and not overwrite the method if it already existed, which ironically ensured that code relying on their custom implementation would break when a standard one was added and didn't behave the same. This all caused an event called &lt;a href="https://developer.chrome.com/blog/smooshgate/"&gt;SmooshGate&lt;/a&gt;, and similar situations are responsible for why some of the other method names in JavaScript are also somewhat odd due to more obvious names being "taken".&lt;/p&gt;

&lt;p&gt;In fact, the very first widely adopted JavaScript library was called &lt;code&gt;Prototype.js&lt;/code&gt;, and one of its selling points was extending the DOM APIs so that DOM Elements would come "batteries included", but it got out-competed by jQuery largely because people realized that native prototype extension is dangerous in that it's fragile and hard to maintain compared to wrappers.&lt;/p&gt;

&lt;p&gt;Since then, monkey patching the built-in objects has been &lt;a href="https://humanwhocodes.com/blog/2010/03/02/maintainable-javascript-dont-modify-objects-you-down-own/"&gt;a long-standing discussion&lt;/a&gt;, with some people still trying to cling on to its promise, but overall the consensus is that it's a bad practice that should be reserved to polyfilling, and that you should only modify objects that you own.&lt;/p&gt;

&lt;h2&gt;
  
  
  Solution: symbol protocol extension 🤯
&lt;/h2&gt;

&lt;p&gt;The concept of protocols is already in use in JavaScript, most notably as as &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols"&gt;iteration protocols&lt;/a&gt;, and there is even a &lt;a href="https://github.com/tc39/proposal-first-class-protocols"&gt;proposal to add first-class support for symbol-based protocols&lt;/a&gt;. I've also made &lt;a href="https://github.com/symbola/symbola"&gt;a proof-of-concept library (Symbola)&lt;/a&gt; for implementing symbol extension in userland, and it actually works nicely, with some caveats. &lt;/p&gt;

&lt;p&gt;Something that should lend legitimacy to this approach is, firstly, that it aligns with similar language features like Swift and Clojure protocols, Rust traits, Haskell typeclasses and others, and, secondly, that it has theoretical grounding in that it &lt;a href="https://www.giacomodebidda.com/posts/3-ways-to-solve-the-expression-problem/#h-open-classes-aka-monkey-patching"&gt;solves the expression problem&lt;/a&gt;. In a nutshell, the expression problem is when you want to both be able to easily extend existing methods to new data types, and to extend new data types with existing methods, &lt;em&gt;all without modifying the source code&lt;/em&gt;, and also while retaining type safety.&lt;/p&gt;

&lt;p&gt;The extension problem is not just an academic exercise, because there's real pragmatic reasons why you are not able to or don't want to modify code but want to extend it, and not owning the code is one of those reasons. This is why, in a sense, the "open classes" and monkey patching in JavaScript are a fix to the expression problem, but you're not supposed to use it because it leads to fragility, namespace collisions and maintenance problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Symbols to the rescue 📯
&lt;/h3&gt;

&lt;p&gt;Symbols are unique and can be used as keys instead of strings while using the same namespace like, for example, &lt;code&gt;Array.prototype&lt;/code&gt;, and define a flatten method that can be accessed only with reference to the unique symbol:&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;flatten&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;flatten&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[].&lt;/span&gt;&lt;span class="nx"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;([],&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="p"&gt;[[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]][&lt;/span&gt;&lt;span class="nx"&gt;flatten&lt;/span&gt;&lt;span class="p"&gt;]();&lt;/span&gt; &lt;span class="c1"&gt;// returns [1, 2, 3]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using interface merging in TypeScript also allows this to be well-typed, and the really interesting things start when building on other protocols:&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;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Symbol&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;map&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;xs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;xs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// logs [2, 3, 4]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suddenly the &lt;code&gt;Set&lt;/code&gt; objects have a map method, but so does every object that inherits from &lt;code&gt;Object.prototype&lt;/code&gt; and conforms the iterable protocol, namely has a &lt;code&gt;[Symbol.iterator]()&lt;/code&gt; method that returns an iterator, and this, too, is easy to express in TypeScript:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt;  &lt;span class="nx"&gt;Mappable&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;Iterable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;A&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;Iterable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;B&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kr"&gt;declare&lt;/span&gt;  &lt;span class="nb"&gt;global&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kr"&gt;interface&lt;/span&gt;  &lt;span class="nb"&gt;Object&lt;/span&gt;  &lt;span class="kd"&gt;extends&lt;/span&gt;  &lt;span class="nx"&gt;Mappable&lt;/span&gt;  &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This means that editors can know to auto-complete the &lt;code&gt;[map]()&lt;/code&gt; method correctly, and the type system will check if the target is actually an iterable, so the support for it is first class.&lt;/p&gt;

&lt;p&gt;In conclusion, the biggest caveat of this approach is probably the unfamiliarity to developers, but it does have a valid use case, and JavaScript and TypeScript so far just seem behind other languages in exploring it.&lt;/p&gt;

&lt;h2&gt;
  
  
  See also
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://codepen.io/slikts/pen/jOQxGWb?editors=0010"&gt;Interactive sandbox for Symbola with usable examples of protocol extension&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/symbola/symbola#readme"&gt;Symbola readme with caveats and more examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://web.archive.org/web/20110821210021/http://www.ibm.com/developerworks/java/library/j-clojure-protocols/"&gt;Detailed discussion of the expression problem in the context of Clojure protocols&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=E-2y1qHQvTg"&gt;Conference talk comparing Rust traits, Swift protocols, Haskell typeclasses and C++ concepts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>prototypes</category>
      <category>symbols</category>
      <category>protocols</category>
    </item>
    <item>
      <title>Deno is probably not worth it right now</title>
      <dc:creator>Reinis Ivanovs</dc:creator>
      <pubDate>Fri, 15 May 2020 16:01:02 +0000</pubDate>
      <link>https://dev.to/slikts/deno-is-probably-not-worth-it-right-now-1gg</link>
      <guid>https://dev.to/slikts/deno-is-probably-not-worth-it-right-now-1gg</guid>
      <description>&lt;p&gt;Deno has been riding a certain hype train since its &lt;a href="https://deno.land/v1"&gt;recent release&lt;/a&gt;, and it's important to look at it critically, first and foremost to avoid investing your limited time in a technology that might not pan out for your requirements and use case.&lt;/p&gt;

&lt;p&gt;The title of this post already gives away the conclusion that Deno is &lt;em&gt;probably&lt;/em&gt; not worth it, but the way I arrived at the conclusion was by trying to like Deno and to see how it could be used to its strengths. This post won't say anything very original, but the intent is to give a concise overview of where Deno fits into the &lt;a href="https://tooling.js.org/"&gt;tooling landscape&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Improved security
&lt;/h2&gt;

&lt;p&gt;A highlight of Deno over Node.js and most other environments is the improved security model: programs don't just get blanket access to the resources available to the current user. I've seen the security improvements dismissed out of hand compared to other approaches like containerization, but it's actually a modern and welcome approach to limit access to resources by default; it should be an increasingly familiar approach going forward, and an another example of it is &lt;a href="https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/"&gt;WASI&lt;/a&gt; using a &lt;a href="https://github.com/WebAssembly/WASI/blob/master/docs/DesignPrinciples.md#capability-based-security"&gt;capability-based security&lt;/a&gt; model.&lt;/p&gt;

&lt;h2&gt;
  
  
  A fresh start for APIs
&lt;/h2&gt;

&lt;p&gt;Outside of security by default, the other major advantage is to be able to break with the legacy aspects of Node.js APIs. To illustrate, this is how you can watch for file system changes using Deno:&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="k"&gt;for&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;paths&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="nx"&gt;Deno&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;watchFs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;paths&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 takes advantage of ES2018 &lt;a href="https://2ality.com/2016/10/asynchronous-iteration.html"&gt;async iteration&lt;/a&gt;, and it even works at the top level without needing to be wrapped in an async function. Setting up the same (excepting the top level part) in Node.js would require boilerplate like this:&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;changes&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;stream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Transform&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;objectMode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;watch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pathname&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;changes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;pathname&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 creates a Node.js stream, which also implements the async iteration protocols and can be used with &lt;code&gt;for-await-of&lt;/code&gt; loops, but you'd have to go out of your way to even know to do this, and usually it'd just be done using a plain callback, which at its worst can lead to the "pyramid of doom" problem. It's not a huge deal, but is an example of how a newer API can feel less "crusty" to use.&lt;/p&gt;

&lt;p&gt;Deno also aims to avoid duplicating existing &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API"&gt;web APIs&lt;/a&gt;, such as &lt;code&gt;fetch()&lt;/code&gt;, which means you can reuse the same API knowledge between platforms, and it should generally be a welcome idea.&lt;/p&gt;

&lt;h2&gt;
  
  
  Dependency management is where it gets less fun
&lt;/h2&gt;

&lt;p&gt;Deno is made by Ryan Dahl, who's also the original developer of Node.js, and, since the outset, the development of Deno has been couched in terms of fixing Node.js pain points, but the &lt;a href="https://youtu.be/M3BM9TB-8yA"&gt;talk that explains the motivation&lt;/a&gt; can also be (only somewhat uncharitably) summarized as "you could make the Node.js implementation simpler by not implementing features, like packages". It's not a compelling point to those relying on the features who would need to find workarounds.&lt;/p&gt;

&lt;p&gt;Deno takes a page out of Go's approach to dependencies and doesn't provide a dependency manager like npm or Rust's cargo; instead of having special module resolution rules like with &lt;code&gt;require()&lt;/code&gt;, modules are just loaded from URLs using the ECMAScript module format, and conventionally are re-exported from a &lt;code&gt;deps.ts&lt;/code&gt; file instead of being listed in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;There's still a way in Deno to create lock files, there's also an optional way to have &lt;a href="https://deno.land/x"&gt;zero-installs&lt;/a&gt; like with Yarn by commiting a &lt;code&gt;$DENO_DIR&lt;/code&gt;, and there's even something that &lt;a href="https://deno.land/x"&gt;vaguely resembles&lt;/a&gt; a centralized registry, so it's all kind of similar while still being different and incompatible with existing tools and approaches in different ways.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compatibility and interoperability are crucial
&lt;/h2&gt;

&lt;p&gt;Deno simplifies its implementation by skipping package management, but then it, for example, has a built-in test runner, which Node.js doesn't. Deno simplifies the Node.js APIs, but then it still needs to provide a complex &lt;a href="https://github.com/denoland/deno/issues/3403"&gt;compatibility layer&lt;/a&gt;, because there's a lot of existing and useful software using Node.js APIs. It's also adding a native plugin feature, although it'll probably never support Node.js native extensions.&lt;/p&gt;

&lt;p&gt;The developer experience in all of this is a stream of "how do I…" and then often discovering that you either just don't, or that it's rudimentary compared to what you're used to (like the built-in Deno test runner compared to something like Jest), or that it half-works (I couldn't get the test runner work in watch mode using &lt;a href="https://deno.land/x/denon/"&gt;Denon&lt;/a&gt;, which is meant to be the alternative to Nodemon).&lt;/p&gt;

&lt;p&gt;For example, npm and Yarn provide &lt;a href="https://docs.npmjs.com/cli/run-script"&gt;package scripts&lt;/a&gt;, which give a set way for users to discover and run commands, but in Deno you'd either have to find &lt;a href="https://github.com/umbopepato/velociraptor"&gt;Velociraptor&lt;/a&gt; (made less easy by the non-descriptive name of the tool), or use Makefiles or just shell scripts, and you'd also possibly be leaving out Windows users.&lt;/p&gt;

&lt;p&gt;A list of issues like this could go on for a long time; some will have workarounds, others are just due to Deno just being released, but overall, if your goal is to get specific tasks done and not just use a "shiny new" tool, the lack of interoperability or compatibility skews the equation against Deno. &lt;/p&gt;

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

&lt;p&gt;It can be helpful for Deno to "shake things up" and, for example, maybe make Node.js improve faster in aspects like modernizing its APIs, and to put the "security by default" model more solidly on the map, but overall Deno is a hard sell from a pragmatic standpoint. It reminds of the situation with Python 3, which brought improvements, but then took a long time to reach wide adoption due to it often just being easier to continue using Python 2.&lt;/p&gt;

&lt;p&gt;Features like first-class support for TypeScript can also be a mixed bag (which I say as someone who generally prefers TypeScript), because use cases like prototyping or one-off scripts can actually benefit from dynamic typing, and it's also not necessarily useful to have type checking in the test runner if you already have it in the editor and the CI, but Deno doesn't yet have a way to selectively turn type checking off.&lt;/p&gt;

&lt;p&gt;Even if you're not using Deno but are a library or tool author, you can look forward to possibly getting bug reports from a new, not fully compatible environment, or requests to support it, which isn't trivial (although the upside is that Deno should hopefully speed up ES module adoption).&lt;/p&gt;

&lt;p&gt;The bottom line is that it's probably better that Deno exists, but its selling points are stretched thin by that it's still new, and that a lot of useful libraries and tools don't work and sometimes can't be ever expected to work.&lt;/p&gt;

</description>
      <category>deno</category>
      <category>node</category>
      <category>typescript</category>
    </item>
  </channel>
</rss>
