<?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: Bogdan Nedelcu</title>
    <description>The latest articles on DEV Community by Bogdan Nedelcu (@bogdanned).</description>
    <link>https://dev.to/bogdanned</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%2F289241%2F39d84fb0-9a94-4b4f-8d15-27c5a40c340a.jpg</url>
      <title>DEV Community: Bogdan Nedelcu</title>
      <link>https://dev.to/bogdanned</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bogdanned"/>
    <language>en</language>
    <item>
      <title>GraphQL at global scale: Facebook</title>
      <dc:creator>Bogdan Nedelcu</dc:creator>
      <pubDate>Thu, 28 May 2020 09:53:58 +0000</pubDate>
      <link>https://dev.to/bogdanned/graphql-at-a-global-scale-facebook-44km</link>
      <guid>https://dev.to/bogdanned/graphql-at-a-global-scale-facebook-44km</guid>
      <description>&lt;h2&gt;
  
  
  From the news:
&lt;/h2&gt;

&lt;p&gt;A few weeks ago Facebook rolled out its new desktop design. &lt;/p&gt;

&lt;p&gt;One of the many improvements they are experimenting with is &lt;code&gt;lazy loading&lt;/code&gt; where they prefetch both the &lt;code&gt;code&lt;/code&gt; and the &lt;code&gt;data&lt;/code&gt; needed by a view.&lt;/p&gt;

&lt;p&gt;What draw my attention is the introduction of &lt;code&gt;entry points&lt;/code&gt;: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"files that wrap a code-split point and transform inputs into queries.&lt;br&gt;
These files are very small and are downloaded in advance for any&lt;br&gt;
reachable code-split point."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The so-called &lt;code&gt;entry points&lt;/code&gt; unify the fetching of &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;data&lt;/code&gt; a view needs in one single GraphQL query:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"This has the added benefit of creating a single JavaScript function&lt;br&gt;
that contains all the data-fetching needs for any given point in the&lt;br&gt;
app, which can be used for the server preloading discussed earlier."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The new approach leverages GraphQL's ability to unity request and minimizes network usage in a way I have never seen before. &lt;/p&gt;

&lt;h2&gt;
  
  
  This literally blew my mind. 🚀
&lt;/h2&gt;

&lt;p&gt;I cannot wait for further releases of their performance improvements and will try to use this in my future projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What do you think?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Have you ever seen code and data fetching done simultaneously?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;More on Facebook's engineering blog &lt;a href="https://engineering.fb.com/web/facebook-redesign/"&gt;here&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>architecture</category>
      <category>javascript</category>
      <category>react</category>
    </item>
    <item>
      <title>The price of software: Unit testing</title>
      <dc:creator>Bogdan Nedelcu</dc:creator>
      <pubDate>Thu, 07 May 2020 07:16:25 +0000</pubDate>
      <link>https://dev.to/bogdanned/the-price-of-software-unit-testing-59i9</link>
      <guid>https://dev.to/bogdanned/the-price-of-software-unit-testing-59i9</guid>
      <description>&lt;p&gt;Test automation is one of the best investments an engineering team can do when developing software. The industry accepts that testing units is the fastest and most simple form to automate tests. But does that mean we should unit test our whole codebase? How much of our code should we cover with unit testing? How can we be most efficient?&lt;/p&gt;

&lt;h3&gt;
  
  
  Measuring Tests Effectiveness
&lt;/h3&gt;

&lt;p&gt;Finding program bugs when developing is cheaper than fixing them afterward. Handling user concerns, maintaining transaction consistency, isolating, and then releasing a patch for a defect is expensive. &lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  The goal of testing is to reduce the cost of software.
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;The difference between the price of process and the cost of bugs is the real return of investment of writing tests.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Coverage
&lt;/h3&gt;

&lt;p&gt;The traditional way to measure how much we are testing is the so-called code coverage. We obtain the value of coverage as the percentage of source code that runs when executing tests.&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%2Fwww.bogdanned.com%2Fmedia%2Fcode_coverage_final.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2Fcode_coverage_final.jpg" title="Code Coverage" alt="code-coverage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In addition to the number of lines of code, different criteria can be used in the coverage calculation: function coverage, statement coverage, and so on. However, they all rely on the ratio of total code versus code executed when running tests as measurement. &lt;/p&gt;

&lt;p&gt;The assumption behind measuring code coverage is that a program which entirely tested will have fewer defects. In practice, aiming for 100% coverage is not very realistic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Testing Fatigue
&lt;/h3&gt;

&lt;p&gt;The cost of writing unit tests increases exponentially as we get closer to 100% coverage. The number of defects detected decreases at the same rate. &lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  Writing tests to get the test coverage from 90% to 100% is expensive and highly ineffective in preventing bugs.
&lt;/h3&gt;
&lt;/blockquote&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%2Fwww.bogdanned.com%2Fmedia%2Ftest_fatigue_final.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2Ftest_fatigue_final.jpg" title="Unit Test Fatigue" alt="unit-test-fatigue"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Aiming for complete test coverage couples the tests with the implementation to a level where development effort for a feature can even double. We get slowly out of sync with product development when we spend too much time testing implementation details.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Cost of Unit Testing
&lt;/h3&gt;

&lt;p&gt;Being unit testing the fastest way to test, we fall in the trap of overusing it. To increase code coverage, we test code that does not correspond to a specific unit but ties many units together. The effort of mocking and stubbing becomes higher than writing the business logic itself. We are at that point writing integration tests using the unit test approach and tools.&lt;/p&gt;

&lt;p&gt;The return on investment of those unit tests is minimal because they rely heavily on mocking of their dependencies and will pass even if those dependencies have changed their interfaces. Making mocks and fakes aware of changes in the constructs they replace results into heavy maintenance work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  Abusing unit testing adds overhead to the development process without reducing defect density.
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is usually much more cost-effective to write an integration test than several unit tests if we already have a decent integration test setup.&lt;/p&gt;

&lt;p&gt;Using the traditional code coverage as a synonym for program correctness or code heath will lead to a negative return on test efforts and increase development time rather than decreasing it.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Effective Code Coverage
&lt;/h3&gt;

&lt;p&gt;Tests are beneficial if they prevent the maximum amount of bugs unit of time invested. Code coverage is only useful if we include the context in the calculation. A better parameter to quantify out test efforts is something we can call the &lt;strong&gt;effective code coverage&lt;/strong&gt;. That is the percentage of code that the development team decided should be unit tested and the ones that execute when running tests.&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%2Fwww.bogdanned.com%2Fmedia%2Feffective_code_coverage_final.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2Feffective_code_coverage_final.jpg" title="Effective Test Coverage" alt="effective-test-coverage"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Depending on the project and the programming language, this metric will not be higher than 20% to 40% of the total source code. That is because we target code that:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;identifies as a unit&lt;/li&gt;
&lt;li&gt;is ideally reused&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Because tests do not suffocate development, the return on investment of this method is much higher. The approach gives space to investing testing time that would normally go into unit assertions in integration or end to end tests.&lt;/p&gt;

&lt;p&gt;This testing philosophy requires flexibility in thinking and relies heavily on context: the kind of software we are writing and its purpose, language, frameworks, and, architecture choices we make. Therefore, the parts of the source code that must be unit tested change with the same frequency as our product does.&lt;/p&gt;

&lt;blockquote&gt;
&lt;h3&gt;
  
  
  Although counter-intuitive, decreasing the amount of unit testing can improve the overall code quality.
&lt;/h3&gt;
&lt;/blockquote&gt;

&lt;p&gt;We should avoid writing unit tests that are too close to implementation details. Instead, focusing on reusable modules and their interfaces will maximize the number of defects identified per unit time.&lt;/p&gt;

&lt;p&gt;Approach unit testing in the same way you approach any form of automation. Traditional process analysis, including cost and time, help make a much better decision than absolute measures of coverage. The remaining testing time can be invested in more sophisticated testing methods, closer to user expectation, and changing less frequently. &lt;/p&gt;

&lt;h3&gt;
  
  
  Summing up
&lt;/h3&gt;

&lt;p&gt;Rather than absolute metrics use context in your decision making. Be intentional about your choices and always keep an open mind. &lt;/p&gt;

&lt;h4&gt;
  
  
  Testing setups with the highest return of investment are a mix of unit, integration, end-to-end, and manual tests. The perfect blend depends on your product, tech stack, and team.
&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Did you enjoyed the content? Follow me on &lt;a href="https://dev.to/bogdanned"&gt;dev.to&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/bogdan-nedelcu/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; to get more of this in your feed. As originally published on &lt;a href="https://www.bogdanned.com/blog" rel="noopener noreferrer"&gt;bogdanned.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>testing</category>
      <category>architecture</category>
      <category>tdd</category>
      <category>microservices</category>
    </item>
    <item>
      <title>The Graph in GraphQL</title>
      <dc:creator>Bogdan Nedelcu</dc:creator>
      <pubDate>Tue, 14 Apr 2020 06:53:49 +0000</pubDate>
      <link>https://dev.to/bogdanned/the-graph-in-graphql-1l99</link>
      <guid>https://dev.to/bogdanned/the-graph-in-graphql-1l99</guid>
      <description>&lt;p&gt;GraphQL is today a ubiquitous choice for building APIs. The technology, open-sourced by Facebook, allows clients to fetch what only they need and aggregates requests under a unique query interface. With GraphQL, we can build faster applications, consume fewer data, and leverage fantastic developer tooling. I have been fascinated by GraphQL ever since its release. However, a question kept coming back to me: &lt;strong&gt;How does it leverage the power of graphs?&lt;/strong&gt; &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bogdanned.com%2Fmedia%2FfirstImage.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2FfirstImage.jpg" title="The Graph In GraphQL" alt="the-graph-in-graphQL"&gt;&lt;/a&gt;In the following lines, we will start by taking a look at graphs, trees, and recursive properties. With that knowledge, let's dive deep into the original specifications and the javascript implementation of the server runtime. We will break apart the inner workings of GraphQL into its most simple and smaller parts and then put them back together. In the process, we will uncover how the data-structures are used to create the technology that changed the web as we know it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Graph?
&lt;/h2&gt;

&lt;p&gt;A long time before GraphQL there where graphs, but what are they exactly? Graphs are data structures that resemble the natural way we build mental models and relate concepts. In graphs, relationships between represented entities are as relevant as the entities themselves.\&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bogdanned.com%2Fmedia%2FrandomGraph.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2FrandomGraph.jpg" title="Graph Example" alt="Graph Example"&gt;&lt;/a&gt;We build graphs with abstract objects called &lt;code&gt;node&lt;/code&gt;s or vertices. The connection between two nodes is called an &lt;code&gt;edge&lt;/code&gt;. We can then explore a &lt;code&gt;graph&lt;/code&gt; recursively following the &lt;code&gt;edges&lt;/code&gt; in a specific order.&lt;/p&gt;

&lt;h3&gt;
  
  
  A-Cyclical Directed Graphs
&lt;/h3&gt;

&lt;p&gt;There are different types of graphs, depending on how the nodes and the edges are arranged. We will focus for now on &lt;strong&gt;a-cyclical directed graphs&lt;/strong&gt; because these are the ones we find in GraphQL. A directed edge has a start and an end and can only be traversed following that direction. Adding direction to the &lt;code&gt;edges&lt;/code&gt; changes the meaning of the relationship between nodes and introduces a hierarchy. &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bogdanned.com%2Fmedia%2FsimpleDirectedGraph.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2FsimpleDirectedGraph.jpg" title="Directed Graph" alt="directed-graph"&gt;&lt;/a&gt; Let's say, for example, we want to represent money loans with a graph. Every edge would represent money borrowed, and the direction would represent the money flow from the lender to the party taking the loan. &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bogdanned.com%2Fmedia%2Fmoney_borrow.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2Fmoney_borrow.jpg" title="Directed Graph Example" alt="directed-graph-example"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  From a Graph to a Tree
&lt;/h2&gt;

&lt;p&gt;Graphs can transform into a different data structure depending on the constraints applied to them. A graph cycle or a circuit is a set of edges where the last edge is also the first edge. When a graph has no cycles is called an a-cyclical graph. A directional graph that is also a-cyclical is known as a &lt;code&gt;tree&lt;/code&gt;. &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%2Fwww.bogdanned.com%2Fmedia%2FgraphVersusTree.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2FgraphVersusTree.jpg" title="From a Graph to a Tree" alt="graph-to-tree"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tree structure has several advantages because of its recursive nature. The elementary unit of a &lt;code&gt;tree&lt;/code&gt; is a &lt;code&gt;root&lt;/code&gt; node and one or many &lt;code&gt;children&lt;/code&gt; nodes. If we model our data as a &lt;code&gt;graph&lt;/code&gt; and impose the necessary constraints on it, we can leverage &lt;code&gt;tree&lt;/code&gt; properties to process it. While one can transverse a &lt;code&gt;tree&lt;/code&gt; as a whole is usually easier to work at a local level, node by node. Read and write operations can be extended to the full length of a &lt;code&gt;tree&lt;/code&gt; by executing functions on the &lt;code&gt;root&lt;/code&gt; node and then recursively on the subsequent &lt;code&gt;children&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Modelling with Graph(QL)
&lt;/h2&gt;

&lt;p&gt;As we all know in &lt;code&gt;GraphQL&lt;/code&gt;, we represent our business domain by using a &lt;code&gt;schema&lt;/code&gt;. The schema itself is a &lt;code&gt;graph&lt;/code&gt; composed of &lt;code&gt;type&lt;/code&gt;s representing different entities. Types are extracted from a problem space using domain-driven techniques. They can have different fields, and every &lt;code&gt;field&lt;/code&gt; points again to another type.  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bogdanned.com%2Fmedia%2FextractingGraphQLType.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2FextractingGraphQLType.jpg" title="GraphQL Type" alt="GraphQL Type"&gt;&lt;/a&gt; In the picture above you can see that &lt;code&gt;lastname&lt;/code&gt;, &lt;code&gt;firstname&lt;/code&gt; and &lt;code&gt;email&lt;/code&gt; point to the &lt;code&gt;scalar&lt;/code&gt; type &lt;code&gt;String&lt;/code&gt;. &lt;code&gt;Scalar&lt;/code&gt; types do not have any subfields and they represent the leaves of the &lt;code&gt;query&lt;/code&gt; tree. A path through the schema will always resolve in a collection of scalars structured like a &lt;code&gt;tree&lt;/code&gt;. Most GraphQL implementations allow developers to add their own &lt;code&gt;scalars&lt;/code&gt; with custom validation and serialization functions. The relationships between a &lt;code&gt;type&lt;/code&gt; and its fields are unidirectional edges and are the building block of the schema. That makes the GraphQL Schema an &lt;code&gt;acyclic directed graph&lt;/code&gt;. As we mentioned before this kind of graph can be read like a tree, visiting each tree once, in a process called &lt;strong&gt;tree traversal&lt;/strong&gt;.  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bogdanned.com%2Fmedia%2Fschema%26query.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2Fschema%26query.jpg" title="GraphQL Schema and Query" alt="GraphQL Schema and Query"&gt;&lt;/a&gt; A GraphQL &lt;code&gt;query&lt;/code&gt; is a path in the graph, going from the root type to its subtypes until we reach scalar types with no subfields. As a result, a &lt;code&gt;query&lt;/code&gt; is a projection of a certain subset of the GraphQL schema to a tree. On the backend side, every field of a type maps to a &lt;code&gt;resolver&lt;/code&gt; function that returns its value when queried.  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bogdanned.com%2Fmedia%2Fresolvers.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2Fresolvers.jpg" title="GraphQL Resolvers" alt="GraphQL Resolvers"&gt;&lt;/a&gt; The &lt;code&gt;query&lt;/code&gt; result is created by merging the result of running &lt;code&gt;resolver&lt;/code&gt; functions for every field extracted from the schema. GraphQL, however, does not stop here. &lt;code&gt;Tree&lt;/code&gt; properties and recursive functions are used not only to model data but mainly to validate and execute queries on that schema.&lt;/p&gt;

&lt;h2&gt;
  
  
  Schema parsing
&lt;/h2&gt;

&lt;p&gt;The GraphQl server parses the schema document at execution time. Types are extracted and stored as plain Javascript &lt;code&gt;Objects&lt;/code&gt; with references to their fields, and to the resolver functions in a &lt;strong&gt;dictionary&lt;/strong&gt; called &lt;code&gt;typeMap&lt;/code&gt;. When a field must be resolved &lt;strong&gt;the execution algorithm&lt;/strong&gt; will look for it in the dictionary and use both the &lt;code&gt;resolver&lt;/code&gt; function and the references to its subtypes to build its value.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="c1"&gt;// Simplified structure of the type map&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;typeMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;rootType&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// array with the fields of the root ype&lt;/span&gt;
      &lt;span class="na"&gt;user&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;lastname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
            &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({})&lt;/span&gt;  &lt;span class="c1"&gt;// points to a resolve function for the type&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="na"&gt;settings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;membership&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...},&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({})&lt;/span&gt;  &lt;span class="c1"&gt;// points to a resolve function for the type&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;As every &lt;code&gt;type&lt;/code&gt; contains a reference to its &lt;code&gt;resolver&lt;/code&gt; function, one can resolve the whole schema by repeating three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Retrieve a &lt;code&gt;type&lt;/code&gt; from the &lt;code&gt;typeMap&lt;/code&gt; dictionary&lt;/li&gt;
&lt;li&gt;Run its &lt;code&gt;resolver&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;Repeat the same on the &lt;code&gt;field&lt;/code&gt;s of this &lt;code&gt;type&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To sum up: the GraphQL schema document is parsed on the server. During the parsing process, the types extracted and stored together with references to its &lt;code&gt;resolver&lt;/code&gt; functions in a dictionary called &lt;code&gt;typeMap&lt;/code&gt;. Because of its tree-like structure, the dictionary can be read and wrote using recursive functions following different transversals.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query Parsing
&lt;/h2&gt;

&lt;p&gt;The GraphQL server parses every query from a &lt;code&gt;string&lt;/code&gt; to an &lt;strong&gt;Abstract Syntax Tree(AST)&lt;/strong&gt;. An AST is a tree representation of the syntax of source code from a particular language. Every node in the tree represents a statement in the &lt;code&gt;query&lt;/code&gt;, including its type, arguments, and position.  &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%2Fwww.bogdanned.com%2Fmedia%2FAbstractSyntaxTree.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2FAbstractSyntaxTree.jpg" title="Abstract Syntax Tree" alt="Abstract Syntax Tree"&gt;&lt;/a&gt; The &lt;code&gt;AST&lt;/code&gt; is a common abstraction for compilers and is used to validate syntax correctness in a process called &lt;strong&gt;semantic analysis&lt;/strong&gt;. Again, because of its tree-like structure, the &lt;code&gt;AST&lt;/code&gt; can be processed and interpreted by recursive functions. This process is behind the &lt;code&gt;query&lt;/code&gt; validation feature that GraphQL editors usually offer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query Execution
&lt;/h2&gt;

&lt;p&gt;Once a &lt;code&gt;query&lt;/code&gt; operation has been converted to an &lt;code&gt;AST&lt;/code&gt; and its structure validated, we can use the &lt;code&gt;tree&lt;/code&gt; properties to execute the &lt;code&gt;query&lt;/code&gt;. The core of the execution algorithm is a recursive function that runs on every node of the query tree following a &lt;strong&gt;&lt;a href="https://en.wikipedia.org/wiki/Depth-first_search" rel="noopener noreferrer"&gt;depth-first-search order&lt;/a&gt;&lt;/strong&gt;.&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bogdanned.com%2Fmedia%2FQueryTraversal.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2FQueryTraversal.jpg" title="Query Tree Traversal" alt="Query Tree Traversal"&gt;&lt;/a&gt;&lt;br&gt;
The traversal ensures that fields are executed and resolved in a stable and consistent order. Following the first order traversal the field execution function will be called on each field in the following sequence: &lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bogdanned.com%2Fmedia%2FExecutionTraversalOrder.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2FExecutionTraversalOrder.jpg" title="Traversal Result" alt="Traversal Result"&gt;&lt;/a&gt; The &lt;code&gt;executeField&lt;/code&gt; function contains the magic behind the field value resolution and is well described in the &lt;a href="https://spec.graphql.org/June2018/#ExecuteField()" rel="noopener noreferrer"&gt;GraphQL specifications&lt;/a&gt;. The function arguments are the &lt;code&gt;name&lt;/code&gt; of the &lt;code&gt;type&lt;/code&gt; is being run on, the definition of that type from the &lt;code&gt;typeMap&lt;/code&gt; dictionary and the &lt;code&gt;resolver&lt;/code&gt; function.  First, the algorithm executes the &lt;code&gt;resolver&lt;/code&gt; function and stores the return. Next, it completes the field value depending on its &lt;code&gt;type&lt;/code&gt;. If the field type is a &lt;code&gt;scalar&lt;/code&gt;, its value is simply "coerced" using a serialization function and directly returned.  &lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fwww.bogdanned.com%2Fmedia%2FExecuteField.jpg" 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%2Fwww.bogdanned.com%2Fmedia%2FExecuteField.jpg" title="Field Execution Algorithm" alt="GraphQL Field Execution Algorithm"&gt;&lt;/a&gt; If the field type is an &lt;code&gt;Object&lt;/code&gt; the &lt;code&gt;completeValue&lt;/code&gt;  process is started. The function &lt;code&gt;collectFields&lt;/code&gt; assembles all the subfields on the respective object type that have not been resolved by the &lt;code&gt;resolver&lt;/code&gt; function and returns a &lt;code&gt;fieldGroup&lt;/code&gt;, an &lt;code&gt;array&lt;/code&gt; ordered respecting the &lt;strong&gt;depth‐first‐search&lt;/strong&gt; style. Then &lt;code&gt;executeField&lt;/code&gt; runs recursively on each one of the subfields collected, in parallel. Finally, the algorithm merges and coerces the values returned by the first execution of the &lt;code&gt;resolver&lt;/code&gt; function and the &lt;code&gt;completeValue&lt;/code&gt; return and builds the final result according to the order in the query &lt;code&gt;AST&lt;/code&gt; tree. &lt;/p&gt;

&lt;p&gt;The resolution algorithm described above is a simplification of the GraphQL specifications. Proper &lt;code&gt;error&lt;/code&gt; handling and response building make the actual implementation more tricky. Parsing queries into trees simplifies the resolution algorithm by leveraging recursiveness and ensures the consistency of field execution for queries on schemas of any shape and size.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summing up
&lt;/h2&gt;

&lt;p&gt;Graphs are the core reason why GraphQL is such a great choice to build and consume APIs. On the one hand, graphs allow developers to model the data in a natural way using directional relationships and hierarchies. The GraphQL Schema is a direct representation of a problem space based on natural language.  &lt;/p&gt;

&lt;p&gt;On the other hand, GraphQL leverages the recursive properties of AST trees to validate and execute queries. The depth first-order transversal of query trees enables stable and predictable parallel data fetching. The recursive nature of queries enabled fast development of tools like GraphiQL and the Apollo Client that leverage it for client-side query validation, caching and cache invalidation. &lt;/p&gt;

&lt;h2&gt;
  
  
  Final thoughts
&lt;/h2&gt;

&lt;p&gt;To build exceptional software we need a fundamental understanding of the tools we use. It is usually simple pieces put together in harmony that make up sophisticated technology. The core abstraction in GraphQL is the graph. A linear algebra concept used to represent information in a non-linear and hierarchical way, or simply put: how we think about it every other day.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Even more fascinating is the fact that at the core of any technology we find the incredible ways humans solve problems naturally.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Originally published on &lt;a href="https://www.bogdanned.com/blog" rel="noopener noreferrer"&gt;bogdanned.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>graphql</category>
      <category>javascript</category>
      <category>node</category>
      <category>architecture</category>
    </item>
    <item>
      <title>On Deno and the future of Node</title>
      <dc:creator>Bogdan Nedelcu</dc:creator>
      <pubDate>Tue, 18 Feb 2020 08:13:00 +0000</pubDate>
      <link>https://dev.to/bogdanned/on-deno-and-the-future-of-node-1l0p</link>
      <guid>https://dev.to/bogdanned/on-deno-and-the-future-of-node-1l0p</guid>
      <description>&lt;p&gt;What would Node look like if it was written today? In one word: &lt;a href="https://deno.land/"&gt;&lt;strong&gt;Deno&lt;/strong&gt;&lt;/a&gt;. The JS runtime has Typescript build in and simplifies module resolution. On top, it takes security to the next level and closes the gap between how we write javascript on the backend and the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not so long ago ...
&lt;/h2&gt;

&lt;p&gt;Released in 2009 node took over the world incredibly fast. Despite the initial skepticism about running javascript in the backend, the community backup was unrivaled. Soon, sophisticated tooling appeared, and years later(2014), Microsoft released Typescript, double betting on Javascript.&lt;/p&gt;

&lt;p&gt;Today, Node is one of the most popular choices for backend development. The event-based server philosophy ensures a high performance/throughput ratio. Running Javascript makes is an accessible tool for many developers. In a way, one can say, Node democratized backend development by lowering the barrier of entry. I have been happily using Node in the last five years, but at the same time, I wonder what does the future awaits?&lt;/p&gt;

&lt;h2&gt;
  
  
  The new kid around the block: Deno
&lt;/h2&gt;

&lt;p&gt;Started in 2018, the Deno project, as the website states, provides a secure runtime for Javascript and Typescript. It is composed of basically two parts: a typescript frontend and a Rust backend. The communication between the two happens by messaging with &lt;code&gt;TypedArrays&lt;/code&gt;.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ISia7qy9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/aqzvipzkxwk1v45n22s9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ISia7qy9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/i/aqzvipzkxwk1v45n22s9.png" alt="Alt Text" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Deno is a JavaScript/TypeScript runtime with secure defaults and a great developer experience. — The Deno Website&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Under the hood, we find a snapshotted version of the Typescript compiler, the V8 engine, and the Tokio event loop. Altogether, shipped as one binary of less than ten MB or as a Rust crate.&lt;/p&gt;
&lt;h2&gt;
  
  
  Ageing API's
&lt;/h2&gt;

&lt;p&gt;Removing promises from Node back in 2010, helped the community at is early stage. But as javascript started to move faster and faster and introducing the await and async functionalities, Node's APIs started to age.&lt;/p&gt;

&lt;p&gt;A considerable effort is made today to bring them up to speed and keep consistent versioning at the same time. Many of the API calls must still be wrapped in constructors like &lt;code&gt;promisify&lt;/code&gt; to be used with the &lt;code&gt;Promise&lt;/code&gt; syntax. This extra step adds overhead to development and increases boilerplate in applications.&lt;/p&gt;

&lt;p&gt;In contrast, Promises are Deno's native bindings for async behavior. The Rust backend mirrors the promise objects received from the Typescript frontend with Rust Futures. Async actions in Deno always return a &lt;code&gt;Promise&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another noticeable thing about Node is that it relies on &lt;code&gt;Buffer&lt;/code&gt; objects to read and write data. In a step to bring uniformity with browser interfaces, Deno uses &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays"&gt;&lt;code&gt;TypedArrays&lt;/code&gt;&lt;/a&gt; everywhere. Being consistent when reading and writing files across the backend and front end is much easier when using the same data structures.&lt;/p&gt;
&lt;h2&gt;
  
  
  Typescript with Zero Setup
&lt;/h2&gt;

&lt;p&gt;If you use Typescript, you know it is a remarkable tool. It introduces a type system that can be enforced as applications grow. This reduces the overhead of conventional static typing by providing flexibility. A project can be partially typed in the begging, and type coverage can be extended as the application grows.&lt;/p&gt;

&lt;p&gt;In Node, Typescript can be used directly with &lt;code&gt;ts-node&lt;/code&gt;, although one must be careful in production. The safest and most performant choice is to use &lt;code&gt;ts-node&lt;/code&gt; for development. Then compile to javascript for production. The setup for development can be complicated, especially together with other features like hot code reloading.&lt;/p&gt;

&lt;p&gt;On the other hand, Deno is all about Typescript. It uses a snapshotted version of the compiler and catches unchanged files. Do you want to run Typescript code? Just run the Deno binary. No config. No hustle. Is that easy, and of course it supports javascript too.&lt;/p&gt;
&lt;h2&gt;
  
  
  Browser Like Package Resolution
&lt;/h2&gt;

&lt;p&gt;The current resolution scheme of Node overcomplicates module resolution. The algorithm provides flexibility in file location and naming with a considerable tradeoff in complexity.&lt;/p&gt;

&lt;p&gt;A &lt;code&gt;require&lt;/code&gt; call would first search for a file with the same name and a &lt;code&gt;.js&lt;/code&gt;, &lt;code&gt;.json&lt;/code&gt;, or &lt;code&gt;.node&lt;/code&gt; extension. If the path specified does not include a leading &lt;code&gt;'/'&lt;/code&gt;, &lt;code&gt;'./'&lt;/code&gt;, or &lt;code&gt;'../'&lt;/code&gt; node assumes the module is a core module or a dependency in the &lt;code&gt;node_modules&lt;/code&gt; folder. If the name does not match, a core module node will check the node_modules at that location. If nothing is found, it will get to the parent directory and continue to do so until it reaches the root of the file system.&lt;/p&gt;

&lt;p&gt;Additionally, folders can be specified as modules in the &lt;code&gt;package.json&lt;/code&gt; file. The &lt;code&gt;require&lt;/code&gt; function is also aware of the &lt;code&gt;package.json&lt;/code&gt; file of all the folder begins checked. Once a folder is found, Node will look for an&lt;code&gt;index.js&lt;/code&gt; or &lt;code&gt;index.node&lt;/code&gt; file inside it. The freedom of not having to provide a file extension and the flexibility of &lt;code&gt;package.json&lt;/code&gt; comes at a considerable increase in complexity and decrease in performance.&lt;/p&gt;

&lt;p&gt;Deno simplifies the algorithm by providing two types of module resolution, relative and URL based:&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;import&lt;/span&gt; &lt;span class="o"&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;https://deno.land/std/testing/asserts.ts&lt;/span&gt;&lt;span class="dl"&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 addition, the resolution algorithm does not use &lt;code&gt;package.json&lt;/code&gt; file or the &lt;code&gt;node_modules&lt;/code&gt; folder. Instead of &lt;code&gt;require&lt;/code&gt;, it uses ES Modules imports. This allows us to use a modern approach to code management without the need of a pre-compiler and brings us again closer to how Javascript is used in the browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Distributed Package Management
&lt;/h2&gt;

&lt;p&gt;Server-less adoption is at this moment doubling every year. Developers use to split monoliths into microservices. Now we are splitting micro-services into functions. Why? Well, on the one hand, nobody wants to deal with orchestration unless we have too. On the other hand, distributed systems are more flexible and can be changed faster. The bottom line is, applications are becoming systems of smaller and separated parts.&lt;/p&gt;

&lt;p&gt;A typical javascript backend application represents 0.3% of the code is using. The rest is made up of packages in the &lt;code&gt;node_modules&lt;/code&gt; folder. And many are hardly used at runtime. At the same time, the whole ecosystem depends on a centralized package manager: &lt;code&gt;npm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Deno&lt;/strong&gt; brings a distributed approach to package management. Packages can be resolved by URL and catched afterward. Applications are lighter and less dependent on a single and centralized package registry.&lt;/p&gt;

&lt;h2&gt;
  
  
  On Security
&lt;/h2&gt;

&lt;p&gt;When doing backend development, I expect security to work outside the box. The last thing I want to think about is a linter file or node module accessing the network or the file system.&lt;/p&gt;

&lt;p&gt;In Deno, internal functions cannot call V8 API's arbitrarily as they do in Node. The communication between Deno's APIs and the JS engine is centralized and unified with messaging based on typed arrays.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Unless specifically allowed, scripts can't access files, the environment, or the network. — deno.land&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Scripts executed with Deno can access the file system and network only if the user explicitly specifies it. And even better, permission can be given at file, folder level, or network path level with the —allow flag. This offers developers granular control of read and write actions that happen at runtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$ &lt;/span&gt;deno &lt;span class="nt"&gt;--allow-net&lt;/span&gt; https://deno.land/std/examples/echo_server.ts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Security by default is a significant upgrade compared to the "trust" policy applied to dependencies one pulls from &lt;code&gt;npn&lt;/code&gt;. With Deno you can run and develop applications with the confidence that they will do what they are expected to.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summing up
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Deno&lt;/strong&gt; is how Node would look like if it would be built today. It improves security, simplifies module resolution, and runs Typescript. &lt;/p&gt;

&lt;p&gt;As I am writing this article, we are still at version 0.33 and growing fast. I am sure if you are here is because you are to some degree using Node or Javascript. If you are like me, you probably love it. But as they say, to love something truly means to let it go.&lt;/p&gt;

&lt;p&gt;I am looking forward to seeing Deno grow beyond merely a scripting runtime and to hearing about the first experiences in production. As long as developers continue disrupting ourselves, we can always expect faster, more straightforward, and more reliable software.&lt;/p&gt;

&lt;p&gt;Originally published on &lt;a href="https://bogdanned.com/blog"&gt;bogdanned.com&lt;/a&gt;.&lt;/p&gt;

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