<?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: Graham Dyson</title>
    <description>The latest articles on DEV Community by Graham Dyson (@grahamdyson).</description>
    <link>https://dev.to/grahamdyson</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%2F293753%2F5b7b53e2-954e-4065-80c8-bf4a6ac98890.jpeg</url>
      <title>DEV Community: Graham Dyson</title>
      <link>https://dev.to/grahamdyson</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/grahamdyson"/>
    <language>en</language>
    <item>
      <title>should i analyse C# or .NET?</title>
      <dc:creator>Graham Dyson</dc:creator>
      <pubDate>Sun, 26 Apr 2020 10:07:21 +0000</pubDate>
      <link>https://dev.to/grahamdyson/should-i-analyse-c-or-net-1en</link>
      <guid>https://dev.to/grahamdyson/should-i-analyse-c-or-net-1en</guid>
      <description>&lt;p&gt;edit: Unlike the conclusion of the post below, I based the analyzer on C# CaaS and not .NET IL. Its now available to use &lt;a href="https://devsnicket.com/eunice/#csharp"&gt;https://devsnicket.com/eunice/#csharp&lt;/a&gt;. The latter doesn't preserve the order of members of a class either in the dll or pdb. Although, after looking at some open source C# projects, &lt;a href="http://devsnicket.com/eunice/csharp/options/#members"&gt;this capability wasn't used by default&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The software development tool I've been working on called &lt;a href="http://devsnicket.com/eunice"&gt;Eunice&lt;/a&gt; started out with JavaScript analysis. Its designed to support multiple interchangeable analyzers, reusing the tool's measurement, graphical and interactive components. These other components were also written in JavaScript so they are cross-platform. In the earlier phases of development I thought it would be beneficial to follow the practice of &lt;a href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food"&gt;dogfooding&lt;/a&gt;. To see how this looks you can view and interact with Eunice's analysis of itself &lt;a href="http://devsnicket.com/eunice/#dogfooding"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Eunice is now at a level of maturity where I've decided to write another analyzer. With personal experience in C# and .NET, I thought creating an analyzer for them next would be productive for me and useful to others.&lt;/p&gt;

&lt;h1&gt;
  
  
  C# or .NET?
&lt;/h1&gt;

&lt;p&gt;The vast majority of .NET is written using C# which includes a CaaS (Compiler as a Service). Using the syntactic/semantic models provided for source files would allow an analyzer to represent the software how it appears to the developer while they are working.&lt;/p&gt;

&lt;p&gt;Software written with C# is also available in the form of compiled assembly files (.dll) containing CIL (Common Intermediate Language). This has a more restricted set of instructions, but as a result is more verbose. If this verbosity isn't going to add complexity to an analyser the restricted set of instructions might simplify it. Some information from the source code, not necessary to run it, isn't included when compiling; however, this information can be preserved (e.g. for debugging) in a accompanying file (.pdb).&lt;/p&gt;

&lt;p&gt;I believe that using the C# CaaS would be more productive than working with the debug files that accompany the compiled CIL. If the information required to implement an analyzer is readily available from CIL alone (i.e. without the debug files) then that would be even more productive.&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  source code directories and namespaces
&lt;/h2&gt;

&lt;p&gt;Structure in the form of nested groups, can be specified both in the source code directories and in namespaces. Both of these parallel ways of structuring software are normally used, but don't have to match. &lt;/p&gt;

&lt;p&gt;Its possible to use both, have a structure that matches everywhere else, but then use one to insert additional groups not present in the other. Even if discrepancies are constrained this way, the variation still adds potential for confusion when navigating a code base.&lt;/p&gt;

&lt;p&gt;If the structures are different, representing both simultaneously would require 4 dimensions (2 x 2D) and would be confusing. To avoid this in the analyzer, one will be chosen over the other. The analyzer will use namespaces, as namespaces are used in C# to reference dependencies not file paths. Namespaces are included in CIL so only .NET analysis is required and not C#. For reference, source code paths aren't included in CIL, but are available from the accompanying debug files.&lt;br&gt;
&lt;a&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  language features
&lt;/h2&gt;

&lt;p&gt;Some C# language features are represented in CIL with additional structure not found in the original code. Some of this additional structure will contain only generated instructions; however, in other cases compiler output for pieces of the original C# will be placed within these generated structures. CIL has meta-data to mark structure as compiler generated with an attribute. Regardless of the attributes presence or methods being entirely generated, there may still be dependencies that need including in the analysis.&lt;/p&gt;

&lt;p&gt;I've created the tables and lists below of C# features and how they are represented in CIL:&lt;/p&gt;

&lt;h3&gt;
  
  
  C# 1
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;feature&lt;/th&gt;
&lt;th&gt;named&lt;/th&gt;
&lt;th&gt;implementation&lt;/th&gt;
&lt;th&gt;generated&lt;/th&gt;
&lt;th&gt;marked&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;delegate&lt;/td&gt;
&lt;td&gt;class&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;extern&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;enum&lt;/td&gt;
&lt;td&gt;class&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;field&lt;/td&gt;
&lt;td&gt;X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;event&lt;/td&gt;
&lt;td&gt;event&lt;/td&gt;
&lt;td&gt;add/remove&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;event (automatic)&lt;/td&gt;
&lt;td&gt;event&lt;/td&gt;
&lt;td&gt;add/remove&lt;/td&gt;
&lt;td&gt;field get/set&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;indexer&lt;/td&gt;
&lt;td&gt;property&lt;/td&gt;
&lt;td&gt;get/set&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;operator overload&lt;/td&gt;
&lt;td&gt;method*&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;property&lt;/td&gt;
&lt;td&gt;property&lt;/td&gt;
&lt;td&gt;get/set&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Not represented in CIL:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;built-in type keywords&lt;/li&gt;
&lt;li&gt;line directive&lt;/li&gt;
&lt;li&gt;region directive&lt;/li&gt;
&lt;li&gt;using directive&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  C# 2
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;feature&lt;/th&gt;
&lt;th&gt;named&lt;/th&gt;
&lt;th&gt;implementation&lt;/th&gt;
&lt;th&gt;generated&lt;/th&gt;
&lt;th&gt;marked&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;iterator/yield&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;method of&lt;/td&gt;
&lt;td&gt;class (nested)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;methods (anonymous)&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;method of&lt;/td&gt;
&lt;td&gt;class (nested)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  C# 3
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;feature&lt;/th&gt;
&lt;th&gt;named&lt;/th&gt;
&lt;th&gt;implementation&lt;/th&gt;
&lt;th&gt;generated&lt;/th&gt;
&lt;th&gt;marked&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;lambda&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;method of&lt;/td&gt;
&lt;td&gt;class (nested)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;property (automatic)&lt;/td&gt;
&lt;td&gt;property&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;field get/set&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;types (anonymous)&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;class (namespace)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  C# 5
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;feature&lt;/th&gt;
&lt;th&gt;named&lt;/th&gt;
&lt;th&gt;implementation&lt;/th&gt;
&lt;th&gt;generated&lt;/th&gt;
&lt;th&gt;marked&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;async/await&lt;/td&gt;
&lt;td&gt;method&lt;/td&gt;
&lt;td&gt;method of&lt;/td&gt;
&lt;td&gt;class (nested)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  C# 6
&lt;/h3&gt;

&lt;p&gt;Not represented in CIL: using directive (static)&lt;/p&gt;

&lt;h3&gt;
  
  
  C# 7
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;feature&lt;/th&gt;
&lt;th&gt;named&lt;/th&gt;
&lt;th&gt;generated&lt;/th&gt;
&lt;th&gt;marked&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;local function&lt;/td&gt;
&lt;td&gt;method*&lt;/td&gt;
&lt;td&gt;class&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  C# 8
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;feature&lt;/th&gt;
&lt;th&gt;named&lt;/th&gt;
&lt;th&gt;implementation&lt;/th&gt;
&lt;th&gt;generated&lt;/th&gt;
&lt;th&gt;marked&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;iterator/yield (async/await)&lt;/td&gt;
&lt;td&gt;method&lt;/td&gt;
&lt;td&gt;method of&lt;/td&gt;
&lt;td&gt;class (nested)&lt;/td&gt;
&lt;td&gt;✓&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* name would need inferring / reformatting&lt;/p&gt;

&lt;h3&gt;
  
  
  conclusion
&lt;/h3&gt;

&lt;p&gt;All the features above where a name from the C# is required, have an item in CIL where it or derivative of it is available. Anonymous methods and lambdas might have dependencies, but those would be added to the item representing their parent class.&lt;/p&gt;

&lt;p&gt;Delegates and enums aren't marked as compiler generated and don't have any implementation that would need representing (e.g. sub-items or dependencies).&lt;/p&gt;

&lt;p&gt;Several features move and mix the CIL representing the original C# inside generated methods of generated classes. However, these follow patterns where dependencies of whats generated could be ignored.&lt;/p&gt;

&lt;p&gt;Region and using directives are two features listed above as not represented in CIL that would be very apparent in the C#. Regions could be represented in analysis as an extra level of item grouping and doing so would match how they appear in C# files. Although the use of regions is debatable, their inclusion in Eunice would be a useful demonstration of their characteristics. Using directives and their ability to specify aliases has a significant effect on the potential dependency scope and verbosity of c#.&lt;/p&gt;

&lt;p&gt;Based on the findings above, speed of the analyzers development will be prioritized over inclusion of region and using directive analysis. I think there is value in those two features, but it'll be more productive for them to be included in a C# CaaS based analyzer, if one were to be developed in the future.&lt;/p&gt;

&lt;p&gt;Graham Dyson - creator of &lt;a href="http://devsnicket.com/eunice"&gt;Eunice&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
      <category>architecture</category>
      <category>programming</category>
    </item>
    <item>
      <title>Polly.JS dependencies with Eunice</title>
      <dc:creator>Graham Dyson</dc:creator>
      <pubDate>Thu, 16 Apr 2020 11:48:51 +0000</pubDate>
      <link>https://dev.to/grahamdyson/eunice-infers-polly-js-1532</link>
      <guid>https://dev.to/grahamdyson/eunice-infers-polly-js-1532</guid>
      <description>&lt;p&gt;In this post I'll demonstrate the development tool &lt;a href="https://devsnicket.com/eunice" rel="noopener noreferrer"&gt;Eunice&lt;/a&gt; by using it on the JavaScript library &lt;a href="https://netflix.github.io/pollyjs" rel="noopener noreferrer"&gt;Polly.JS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I've previously posted a case study about using &lt;a href="https://devsnicket.com/eunice/case-studies/react" rel="noopener noreferrer"&gt;Eunice on React&lt;/a&gt;; however, it wasn't a great introduction to Eunice. It had a few configuration steps, React is more complicated and there was quite a lot to show in Eunice.&lt;/p&gt;

&lt;p&gt;There is also a new feature in &lt;a href="https://devsnicket.com/eunice/javascript/releases#7.3.0" rel="noopener noreferrer"&gt;Eunice 7.3&lt;/a&gt; that can automatically infer potential structure from dependencies. Before the feature, this structure only existed for files and directories when specified by manually writing YAML. This was the case even when the source code being analyzed already had coordinated uni-directional dependencies.&lt;/p&gt;

&lt;p&gt;Eunice analyzes JavaScript source code, so I cloned the 0003c0e commit from the GitHub repository &lt;a href="https://github.com/Netflix/pollyjs" rel="noopener noreferrer"&gt;https://github.com/Netflix/pollyjs&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/Netflix/pollyjs.git pollyjs-eunice
cd pollyjs-eunice
git reset --hard 0003c0e
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Eunice can be downloaded from NPM and run without installing using NPX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx eunice
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The analysis will output a eunice.html file. Opening the file for Polly.JS in a browser shows the following:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0hli11agfcboetdlgx4c.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0hli11agfcboetdlgx4c.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the left a text editor is displaying 6,927 lines of &lt;a href="http://devsnicket.com/eunice/advanced/yaml" rel="noopener noreferrer"&gt;YAML&lt;/a&gt; produced by Eunice's analysis of Polly.JS.&lt;/p&gt;

&lt;p&gt;On the right is a graphical representation of all the &lt;a href="http://devsnicket.com/eunice/dependencies" rel="noopener noreferrer"&gt;dependencies&lt;/a&gt; and the root directories in Polly.JS. The green and red count arrows represent the dependencies, categorized as follows:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6ktm5szh6w81ji85mb54.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F6ktm5szh6w81ji85mb54.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The 1,102 matching (green) and only 22 (red) mismatching dependencies shows that Eunice has found the vast majority of dependencies in Polly.JS as uni-directional. The few bi-directional dependencies that have been found are deep inside the directory structure (e.g. the 17 in packages) and unlikely to be of much, if any consequence.&lt;/p&gt;

&lt;p&gt;There isn't a stack in the root directory shown above; however, selecting the packages/@pollyjs sub-directory will show one for its contents:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fncuea3s2gry90ka41ibe.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fncuea3s2gry90ka41ibe.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The arrangement of 5 levels shown above isn't specified in the source code and has been inferred by Eunice. It will only do this when items have uni-directional dependencies.&lt;/p&gt;

&lt;p&gt;Even without any prior knowledge of how Polly.JS works, the relationship between many of the directories seems intuitive. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;cli is in the top level as its likely to be a way of running other things.&lt;/li&gt;
&lt;li&gt;core is in the middle level, its probably built on by other parts of the project, but also uses some of the lower level functionality it shares with the rest of the project.&lt;/li&gt;
&lt;li&gt;adapter and persister are in the second to bottom level. Their names are less specific than the other adapters and persisters, so the others probably extend them.&lt;/li&gt;
&lt;li&gt;utils is on its own in the bottom level, as it is used elsewhere, but doesn't use anything itself.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The dependencies that Eunice has found can be investigated by selecting the count arrows, this lists the dependencies included in them. For example the single dependency below cli is on node-server:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F03avlap9cdm17mhwbl58.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F03avlap9cdm17mhwbl58.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Eunice shows count arrows for both sides of a dependency relationship. The dependency in the example above is also included as a dependent in the count of 3 above node-server:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F32mlsxxe46p6l8xs39s9.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F32mlsxxe46p6l8xs39s9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The dependents arrow above core can also be selected to investigate how its used by the items above:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzbx1riconpj41jk390mu.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzbx1riconpj41jk390mu.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The dependents of core seem to be only using it for integration testing and the items above don't appear to use it at runtime. Looking at the &lt;a href="https://netflix.github.io/pollyjs/#/README?id=getting-started" rel="noopener noreferrer"&gt;Polly.JS getting started page&lt;/a&gt;, you can see instead the adapters and persisters above are registered with core at runtime. This looks like a potential &lt;a href="https://en.wikipedia.org/wiki/Dependency_inversion_principle" rel="noopener noreferrer"&gt;inverted dependency&lt;/a&gt; in a form of &lt;a href="https://en.wikipedia.org/wiki/Plug-in_(computing)" rel="noopener noreferrer"&gt;plug-in&lt;/a&gt; relationship.&lt;/p&gt;

&lt;p&gt;The same kind of investigation of dependents can be done for adapter:&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpujrs5ynoeu7simrrkjt.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fpujrs5ynoeu7simrrkjt.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The dependency list shows several of the adapters above use it and looking at the &lt;a href="https://netflix.github.io/pollyjs/#/adapters/custom" rel="noopener noreferrer"&gt;Polly.JS custom adapter page&lt;/a&gt; confirms at least fetch and xhr extend it.&lt;/p&gt;

&lt;p&gt;There is a dependency from core on adapter, but this is just for testing.&lt;/p&gt;

&lt;p&gt;The packages/@pollyjs directory I've investigated above is used for the creation of NPM packages, so its not surprising to see that, at least at runtime, there are uni-directional dependencies. However, what appear to be integration tests across those packages also have uni-directional dependencies.&lt;/p&gt;

&lt;p&gt;Eunice could also be used to investigate inside the sub-directories of packages. Here there is the potential for runtime bi-directional dependencies across the directory structure. As there doesn't appear to be any in Polly.JS I haven't done that in this case study. If you want a demonstration of this please see the &lt;a href="http://devsnicket.com/eunice/case-studies/react" rel="noopener noreferrer"&gt;React case study&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You can interact with the Eunice analysis for this case study &lt;a href="http://devsnicket.com/eunice/case-studies/pollyjs/eunice.html" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Even though Eunice shows Polly.JS as already having uni-directional dependencies, using Eunice can still be beneficial while working on such a project.&lt;/p&gt;

&lt;p&gt;Eunice could show potential for additional structure, making the code more self descriptive, by highlighting commonality that could be named in a new group, for example by moving files and directories into a new directory.&lt;/p&gt;

&lt;p&gt;People new to the project might not realise that dependencies are coordinated and consistent with the directory structure. Viewing the structure and dependencies with Eunice could help raise awareness.&lt;/p&gt;

&lt;p&gt;Instead of Eunice inferring stacks, they could be specified in source control, formalizing the relationships and making it clear to everyone they are intentional.&lt;/p&gt;

&lt;p&gt;Find out more at &lt;a href="https://devsnicket.com/eunice" rel="noopener noreferrer"&gt;https://devsnicket.com/eunice&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Graham Dyson - creator of Eunice&lt;/p&gt;

</description>
      <category>architecture</category>
      <category>productivity</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Test scope and isolation with Eunice</title>
      <dc:creator>Graham Dyson</dc:creator>
      <pubDate>Thu, 09 Jan 2020 17:39:07 +0000</pubDate>
      <link>https://dev.to/grahamdyson/test-scope-and-isolation-with-eunice-47hn</link>
      <guid>https://dev.to/grahamdyson/test-scope-and-isolation-with-eunice-47hn</guid>
      <description>&lt;p&gt;There are often debates on the best way to describe what constitutes a "unit" when unit testing. Considering the scope of tests is an important part of code structure and complementary to how the implementation is grouped.&lt;/p&gt;

&lt;p&gt;Structure is one aspect of software, there must also be dependencies. Dependencies still exist even when clarified with contracts (e.g. APIs, interface types) or are inverted (e.g. plug-ins, dependency injection). However, implementation practices such as these can be helpful to improve test scope and isolation.&lt;/p&gt;

&lt;p&gt;Specifically when testing, issues with scope and isolation can lead to tests with lots of setup (e.g. mocking) and discrepancies between where implementation was changed and what tests were affected by those changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://devsnicket.com/eunice"&gt;Eunice&lt;/a&gt; is designed to bring together the concepts of scope and isolation, through the wider concepts of structure and dependency. It does this by encouraging uni-directional dependencies instead of bi-directional; this includes indirect dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--A1lg7s57--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/94pb7no2iekcjymx1z7x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--A1lg7s57--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/94pb7no2iekcjymx1z7x.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post is a 2nd follow up to an earlier case study that investigated and demonstrated the capabilities of Eunice, by using Eunice on the source code of the JavaScript library React:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://dev.to/grahamdyson/analyzing-the-architecture-of-react-its-structure-and-dependencies-with-eunice-1h8c"&gt;"Analyzing the architecture of React, its structure and dependencies, with Eunice"&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/grahamdyson/grouping-code-with-eunice-2c63"&gt;"Grouping code with Eunice"&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In React the most significant scope of structure seems to be the &lt;a href="https://github.com/facebook/react/tree/master/packages"&gt;packages directory&lt;/a&gt; in the root of its repository. By the end of the case study and the 1st follow up, after looking at the dependencies shown by Eunice, I'd defined a potential stack for the packages directory, this included a new group for devtools. There were still some mismatching dependencies (red up arrows), at the packages scope (arrows outside the grey sub-directory boxes):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8wyKk43U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/gl8tq5hgptef1jpvddzw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8wyKk43U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/gl8tq5hgptef1jpvddzw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;While looking through React's code I noticed some of the package scoped bi-directional dependencies were only in its tests. This can be investigated by modifying the ignore path pattern to exclude test related directories:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npx eunice &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--ignore-path-pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"(^(&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;|babel.config.js|scripts|fixtures)|node_modules|__tests__)"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--modify-stacks-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.eunice-stack-modify.yaml &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--is-file-content-reversed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;classPrivateProperties &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;classProperties &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dynamicImport &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;flow &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jsx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Re-running the analysis and reloading the web page shows that with tests ignored, the number of sub-directories with no bi-directional dependencies at the package scope has improved. Note that Eunice has detected that react-test-renderer no longer needs to be stacked in a separate level and so has automatically moved it up into the level above:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OAhrJL5_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4okizmxog5jn4x8pnmre.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OAhrJL5_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/4okizmxog5jn4x8pnmre.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The remaining red mismatching dependency arrows across packages are from react-flight and react-server onto react-dom. Modifying the packages directory stack can, for the first time, get all the package scoped dependencies uni-directional. This can be done by moving react-flight and react-server below react-dom:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;existing&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;react-devtools-group&lt;/span&gt;
    &lt;span class="na"&gt;dependencyPermeable&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;react-devtools&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-devtools-shell&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;react-devtools-core&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-devtools-inline&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;react-devtools-extensions&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;react-devtools-shared&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;react-art&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-interactions&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-refresh&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;react-test-renderer&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;react-dom&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-native-renderer&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-noop-renderer&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;legacy-events&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-flight&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-reconciler&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-server&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;create-subscription&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;jest-mock-scheduler&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;jest-react&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-cache&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-is&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-stream&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;use-subscription&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;babel-plugin-react-jsx&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;eslint-plugin-react-hooks&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;react-debug-tools&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;scheduler&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;shared&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can now see in Eunice that the only dependencies across the packages sub-directories are those from tests, as there are no package scoped mismatching red arrows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--y_InwUYh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9vkt8tlti558faipbxpi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y_InwUYh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/9vkt8tlti558faipbxpi.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ignoring tests in Eunice has shown a potential uni-directional structure that might work for the implementation. However, ideally and more permanently the tests could be updated in React's code to match such a structure and so be represented in the analysis with importance equal to that of the implementation.&lt;/p&gt;

&lt;p&gt;Find out more at &lt;a href="https://devsnicket.com/eunice"&gt;https://devsnicket.com/eunice&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>testing</category>
      <category>architecture</category>
      <category>react</category>
    </item>
    <item>
      <title>Grouping code with Eunice</title>
      <dc:creator>Graham Dyson</dc:creator>
      <pubDate>Tue, 07 Jan 2020 16:04:52 +0000</pubDate>
      <link>https://dev.to/grahamdyson/grouping-code-with-eunice-2c63</link>
      <guid>https://dev.to/grahamdyson/grouping-code-with-eunice-2c63</guid>
      <description>&lt;p&gt;As software gets more complicated we need ways to structure code to make it easier to understand. For example, functions, classes, closures, files, directories, repositories, namespaces, packages and services. However, how code is grouped in these structures doesn't always fit well with how the pieces work together.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://devsnicket.com/eunice"&gt;Eunice&lt;/a&gt; is designed to help explore and define structure with awareness of the actual dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--eTLdOzoi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/7q28b8rjcym05h5s4ubj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--eTLdOzoi--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/7q28b8rjcym05h5s4ubj.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This post is a follow up to an earlier case study that investigated and demonstrated the capabilities of Eunice, by using Eunice on the JavaScript library React:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/grahamdyson/analyzing-the-architecture-of-react-its-structure-and-dependencies-with-eunice-1h8c"&gt;"Analyzing the architecture of React, its structure and dependencies, with Eunice"&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In React the most significant scope of structure seems to be the &lt;a href="https://github.com/facebook/react/tree/master/packages"&gt;packages sub-directory&lt;/a&gt; in the root of its repository. By the end of the case study I'd defined a potential stack for packages based on the existing directory structure and the dependencies shown by Eunice. However, this structure and its dependency counts didn't look particularly straightforward:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0Pr_rAFf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/daez222qk2j5tr9ispxe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0Pr_rAFf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/daez222qk2j5tr9ispxe.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The packages directory has enough items and levels that it can be hard to remember what all the dependency relationships are. This can be improved by grouping items that share concepts and dependency relationships.&lt;/p&gt;

&lt;p&gt;The six sub-directories highlighted below all relate to devtools, have dependency counts that don't require their distribution across the stack and so could be grouped:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lScV5D0S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/c1tqhe6cvno3p3od7bod.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lScV5D0S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/c1tqhe6cvno3p3od7bod.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To investigate how this might look the Eunice stack file in the packages directory can be modified. I've added a new item named react-devtools-group and moved the six related items inside it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- - existing
- - id: react-devtools-group
    dependencyPermeable: true
    items:
      - [ react-devtools, react-devtools-shell ]
      - [ react-devtools-core, react-devtools-inline ]
      - - react-devtools-extensions
      - - react-devtools-shared
- [ react-art, react-interactions, react-refresh ]
- - react-test-renderer
- [ react-dom, react-native-renderer, react-noop-renderer ]
- [ legacy-events, react-reconciler ]
- [ create-subscription, jest-mock-scheduler, jest-react, react-cache, react-is, react-stream, use-subscription ]
- [ babel-plugin-react-jsx, eslint-plugin-react-hooks, react, react-debug-tools, scheduler, shared ]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I've marked the new item in the YAML as dependencyPermeable so that Eunice's dependency resolution will look inside it even though it won't be specified in the code's import statement paths.&lt;/p&gt;

&lt;p&gt;Re-running the analysis and reloading the web page shows that this makes the packages directory stack simpler without adding any mismatching dependencies:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cQGfDdtR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/l46qidmfxs42ks4960dl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cQGfDdtR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/l46qidmfxs42ks4960dl.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Selecting the new react-devtools-group shows its stack:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7zmiirJa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3f6s4xhuye8939drr0ct.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7zmiirJa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/3f6s4xhuye8939drr0ct.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make this grouping more permanent and obvious, the Eunice stack above could be replaced with a new sub-directory in the code.&lt;/p&gt;

&lt;p&gt;The example above was an obvious group to create, with the shared concept (devtools) already defined, high cohesion within its items and a simple relationship with the rest of the system. To get the same effect elsewhere, more detailed work might be required, directly in the code, moving small pieces around from across many parts of a system. Hopefully Eunice would still be useful even when whats required is more laborious.&lt;/p&gt;

&lt;p&gt;Find out more at &lt;a href="https://devsnicket.com/eunice"&gt;https://devsnicket.com/eunice&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>architecture</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Analyzing the architecture of React, its structure and dependencies, with Eunice</title>
      <dc:creator>Graham Dyson</dc:creator>
      <pubDate>Mon, 16 Dec 2019 09:15:50 +0000</pubDate>
      <link>https://dev.to/grahamdyson/analyzing-the-architecture-of-react-its-structure-and-dependencies-with-eunice-1h8c</link>
      <guid>https://dev.to/grahamdyson/analyzing-the-architecture-of-react-its-structure-and-dependencies-with-eunice-1h8c</guid>
      <description>&lt;p&gt;This case study investigates and demonstrates the capabilities of &lt;a href="https://devsnicket.com/eunice"&gt;Eunice&lt;/a&gt;, by using Eunice on the JavaScript library &lt;a href="https://reactjs.org"&gt;React&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Eunice helps improve software architecture by analyzing, measuring, exploring and defining; structure and dependencies.&lt;/p&gt;

&lt;p&gt;Eunice is based on the premise that software structure and modularity improve when dependencies are unidirectional. Eunice's approach isn't limited to direct dependencies, but includes indirect dependencies as well.&lt;/p&gt;

&lt;p&gt;With Eunice you define an intended structure/architecture, it shows you dependencies that don't match, and you can further refine the definition or update your code to match.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I've based the case study on the &lt;a href="https://github.com/DevSnicket/react/commit/0f3838a01b0fda0ac5fd054c6be13166697a113c"&gt;0f3838a&lt;/a&gt; commit in the React repository. I've created a fork to make it easier if you want to follow along:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/DevSnicket/react.git react-eunice
&lt;span class="nb"&gt;cd &lt;/span&gt;react-eunice
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Eunice can be downloaded from NPM and run without installing using NPX:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npx eunice
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You will be prompted to accept a EULA. Eunice is free to use on open source projects, and its free to use for education and training. Therefore contributions to React and following along with this case study both qualify. There is also an evaluation period to try Eunice out on closed source commercial software.&lt;/p&gt;

&lt;h1&gt;
  
  
  configuration
&lt;/h1&gt;

&lt;p&gt;Running Eunice on React without any parameters will raise the following error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;Error: Analysis of file &lt;span class="s2"&gt;"packages&lt;/span&gt;&lt;span class="se"&gt;\c&lt;/span&gt;&lt;span class="s2"&gt;reate-subscription&lt;/span&gt;&lt;span class="se"&gt;\i&lt;/span&gt;&lt;span class="s2"&gt;ndex.js"&lt;/span&gt; raised the following error.

  Unexpected token, expected &lt;span class="s2"&gt;";"&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;14:5&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This error is raised because React uses &lt;a href="https://flow.org/"&gt;Flow&lt;/a&gt; syntax in its JavaScript. Eunice uses &lt;a href="https://babeljs.io"&gt;Babel&lt;/a&gt; to parse JavaScript and a Flow plug-in can be enabled with the option &lt;a href="https://devsnicket.com/eunice/javascript/options/#babel-parser-plugins"&gt;babel-parser-plugins&lt;/a&gt;. Some of the Babel parser plug-ins are enabled by default and so will also need to be specified so they aren't disabled when enabling Flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npx eunice &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;classPrivateProperties &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;classProperties &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dynamicImport &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;flow &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jsx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Running Eunice with the Babel plug-ins specified above will raise a further error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;Error: Analysis of file &lt;span class="s2"&gt;"scripts&lt;/span&gt;&lt;span class="se"&gt;\p&lt;/span&gt;&lt;span class="s2"&gt;rettier&lt;/span&gt;&lt;span class="se"&gt;\i&lt;/span&gt;&lt;span class="s2"&gt;ndex.js"&lt;/span&gt; raised the following error.

  &lt;span class="s1"&gt;'return'&lt;/span&gt; outside of &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;32:2&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Eunice parses with a &lt;a href="https://babeljs.io/docs/en/options#sourcetype"&gt;Babel source type&lt;/a&gt; of module, but the file specified in the error is a script. The option &lt;a href="https://devsnicket.com/eunice/javascript/options/#ignore-paths"&gt;ignore-path-pattern&lt;/a&gt; can be used to ignore the "script" directory. I've also included the default ignores and one for babel.config.js. The option is specified with double quotes as the pipe character is used in the regular expression.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npx eunice &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--ignore-path-pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"(^(&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;|babel.config.js|scripts)|node_modules)"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;classPrivateProperties &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;classProperties &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dynamicImport &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;flow &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jsx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Analysis with the options above should complete successfully and output a eunice.html file. Opening the file in a browser should show the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gUAbjjpf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tejrrzf7253q97t764fx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gUAbjjpf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tejrrzf7253q97t764fx.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the left a text editor is displaying 78,696 lines of &lt;a href="https://devsnicket.com/eunice/advanced/yaml"&gt;YAML&lt;/a&gt; produced by Eunice's analysis and &lt;a href="https://devsnicket.com/eunice/javascript/processing"&gt;processing&lt;/a&gt; of React.&lt;/p&gt;

&lt;p&gt;On the right is a graphical representation of all the &lt;a href="https://devsnicket.com/eunice/dependencies"&gt;dependencies&lt;/a&gt; and the root directories (fixtures and packages) in React. The green and red count arrows represent the dependencies, categorized as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7UkDyufK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5fg1of35ae3ygraqebb7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7UkDyufK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/5fg1of35ae3ygraqebb7.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  structure
&lt;/h1&gt;

&lt;p&gt;So far, no &lt;a href="https://devsnicket.com/eunice/structure"&gt;structure&lt;/a&gt; has been defined in any stacks, so we see items listed horizontally. Eunice also infers stacks, in JavaScript this includes the order within a file. In the browser, if for example, dangerfile is selected, the contents of the file dangerfile.js are displayed:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QHozeWsk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yw4532pfn903pyhl4ami.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QHozeWsk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/yw4532pfn903pyhl4ami.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The items in the lowest level are all the module import and CommonJS require calls that Eunice automatically moves below the file content. The other two levels have dependencies that don’t match and so have counts shown in red up arrows. By default Eunice expects code within a file to be ordered high level first with more detail as you move down. The option &lt;a href="https://devsnicket.com/eunice/javascript/options/#reverse-files"&gt;is-file-content-reversed&lt;/a&gt; can reverse this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npx eunice &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--is-file-content-reversed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--ignore-path-pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"(^(&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;|babel.config.js|scripts)|node_modules)"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;classPrivateProperties &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;classProperties &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dynamicImport &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;flow &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jsx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The file will then show with all matching green dependency counts (after reloading the browser):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v-soBUXj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/euba3fug23hxqujubvk8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v-soBUXj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/euba3fug23hxqujubvk8.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looking at the root directory, a lot more of Reacts dependencies are now shown as matching in green:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--swPApnH7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/oxzys2s7a00m5yi0g2ln.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--swPApnH7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/oxzys2s7a00m5yi0g2ln.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There are still 1,592 dependencies, shown in a red horizontal arrow, that are between items that don’t have a structure defined yet.&lt;/p&gt;

&lt;p&gt;There are often conventions in codebases and in React there are many instances of directories that are always either above or below all the other directories. One example is that the &lt;strong&gt;tests&lt;/strong&gt; directory depends on what it tests. Another example is that the rest of the code depends on the shared directory. This is represented below in YAML, with “existing” being used as placeholder for items not specified:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;forks&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;__tests__&lt;/span&gt; &lt;span class="pi"&gt;]&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;existing&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;src&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;shared&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The YAML above can be saved into a file (.eunice-stack-modify.yaml) and that file can be specified with the &lt;a href="https://devsnicket.com/eunice/javascript/options/#modify-stacks"&gt;modify-stacks-file&lt;/a&gt; option so that Eunice modifies all stacks with the following option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npx eunice &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--modify-stacks-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.eunice-stack-modify.yaml &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--is-file-content-reversed&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--ignore-path-pattern&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"(^(&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;|babel.config.js|scripts)|node_modules)"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;classPrivateProperties &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;classProperties &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dynamicImport &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;flow &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--babel-parser-plugins&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;jsx
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You can see examples of what effect this has in React by looking inside packages/react-interactions/events and its sub-directory src/dom:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--f-PYRuLl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ihe063wx74l4i7zujxva.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--f-PYRuLl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ihe063wx74l4i7zujxva.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PIqOPCyK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ynxk0fs58lr4ht6r7m3x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PIqOPCyK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/ynxk0fs58lr4ht6r7m3x.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This reduces the count of mismatching dependencies in the red horizontal arrow by over a third, from 1,592 to 903:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5Zk5DlJf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tnrprsz90nnvskr6fju9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5Zk5DlJf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/tnrprsz90nnvskr6fju9.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;YAML stack files of structure like the one above can also be created for individual directories. Eunice automatically does this when files named .eunice-stack.yaml are saved with the code. I’ve worked through React and created 36 stack files. If you want to view the files I’ve created a branch called with-stacks was created and the stack files added in commit &lt;a href="https://github.com/DevSnicket/react/commit/4dffcae81fdcfa8d288bd350d74517bd6d7d4a26"&gt;4dffcae&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The stacks have removed all the remaining 903 unstructured dependencies; however, I wasn’t able to define structures that would make all dependencies go in the same direction. These mismatching dependencies are shown in the red up arrow count of 815 below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--o9tbeg_S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/c0ju903uu3xnaiyrj00p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--o9tbeg_S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/c0ju903uu3xnaiyrj00p.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see more specific dependency count arrows and the structure I chose, by looking inside the packages sub-directory:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p5xbxG3P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/221v9g6i9bn3ia88q683.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p5xbxG3P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/221v9g6i9bn3ia88q683.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can interact with the result of this case study &lt;a href="https://devsnicket.com/eunice/case-studies/eunice.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Ideally all dependencies should be matching, shown as counts only in the green down arrows and no red arrows. This would be a demonstration (as far as Eunice JavaScript analysis is currently capable) that dependencies were all unidirectional, including indirect dependencies.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ez5Qf3ql--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y6cv6gceyjifw4p05wyp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ez5Qf3ql--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/y6cv6gceyjifw4p05wyp.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;An example of software that’s close to having only unidirectional dependencies is Eunice itself, you can see this by looking at its &lt;a href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food"&gt;dogfooding&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--29cu2mYN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/7t8bprq0eo8rrc1e1f1p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--29cu2mYN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/7t8bprq0eo8rrc1e1f1p.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can interact with Eunice’s dogfooding &lt;a href="https://devsnicket.com/eunice/dogfooding"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The structures I’ve chosen for React are what I think are best fit for the current dependencies. This structure might not be ideal for React and its future development. It might be beneficial to structure differently, which would have higher counts of current mismatching dependencies, but would encourage contributors to change the code and its dependencies to better match that intended structure.&lt;/p&gt;

&lt;p&gt;I defined these structures for React as an individual; however, by committing stack files to source control and running Eunice (e.g. in continuous integration), teams could collaborate and collectively define and improve the structure.&lt;/p&gt;

&lt;p&gt;Follow ups to this post are available:&lt;br&gt;
&lt;a href="https://dev.to/grahamdyson/grouping-code-with-eunice-2c63"&gt;Grouping code with Eunice&lt;/a&gt;&lt;br&gt;
&lt;a href="https://dev.to/grahamdyson/test-scope-and-isolation-with-eunice-47hn"&gt;Test scope and isolation with Eunice&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Thanks for reading
&lt;/h1&gt;

&lt;p&gt;The case study isn’t intended as a commentary or critique of React. Decisions made during it are constrained by the authors understanding of React. With more insight into React, different choices might be made if Eunice was used by its contributors.&lt;/p&gt;

&lt;p&gt;Suggestions to improve the case study are welcome. Hopefully it’s helpful to React contributors or to those who have an interest in React.&lt;/p&gt;

&lt;p&gt;By Graham Dyson - creator of Eunice&lt;/p&gt;

&lt;p&gt;Find out more at &lt;a href="https://devsnicket.com/eunice"&gt;https://devsnicket.com/eunice&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>architecture</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
