<?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: Hiroki Osame</title>
    <description>The latest articles on DEV Community by Hiroki Osame (@privatenumber).</description>
    <link>https://dev.to/privatenumber</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%2F599629%2Fd0c716c5-d418-49ee-8116-08e69790ca17.png</url>
      <title>DEV Community: Hiroki Osame</title>
      <link>https://dev.to/privatenumber</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/privatenumber"/>
    <language>en</language>
    <item>
      <title>Introducing pkg-size.dev</title>
      <dc:creator>Hiroki Osame</dc:creator>
      <pubDate>Tue, 07 Nov 2023 15:00:00 +0000</pubDate>
      <link>https://dev.to/privatenumber/introducing-pkg-sizedev-2hlf</link>
      <guid>https://dev.to/privatenumber/introducing-pkg-sizedev-2hlf</guid>
      <description>&lt;h2&gt;
  
  
  "npm dependencies are too large"
&lt;/h2&gt;

&lt;p&gt;If you've worked with JavaScript and &lt;a href="https://npmjs.com"&gt;npm&lt;/a&gt;, you're likely familiar with the notorious &lt;code&gt;node_modules&lt;/code&gt; directory. This folder houses all your project's dependencies, and is widely known for its hefty size. It's not uncommon for a small project to exceed 100MB, and a quick Google search &lt;a href="https://stackoverflow.com/questions/64234215/node-modules-size"&gt;reveals&lt;/a&gt; &lt;a href="https://www.reddit.com/r/Angular2/comments/8x8efe/node_modules_is_far_far_too_large_no_idea_how_to/"&gt;many&lt;/a&gt; &lt;a href="https://stackoverflow.com/questions/50206572/how-to-reduce-node-modules-in-npm"&gt;frustrated&lt;/a&gt; &lt;a href="https://stackoverflow.com/questions/68236832/node-modules-folder-unnecessarily-large"&gt;devs&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ikfs7UnM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8mr8439peve265jkdmqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ikfs7UnM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8mr8439peve265jkdmqr.png" alt="Meme about node_modules size" width="800" height="575"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;em&gt;A popular meme about `node_modules`&lt;/em&gt;&lt;/center&gt;




&lt;p&gt;While this problem can be improved by npm, the root problem lies within the individual packages installed. Most package authors don't intend to create bulky packages, but they may also not be cognizant of how a few unassuming files in their package can contribute an unwieldy &lt;code&gt;node_modules&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;This problem is also not limited to developers. If you're making a website, these packages are typically bundled together. Inefficiently designed packages will bloat your application and result in slower load times for your users.&lt;/p&gt;

&lt;p&gt;To address this situation, the first step is to enter the &lt;code&gt;node_modules&lt;/code&gt; directory. However, navigating through countless directories with obscure names, each containing numerous files, can be a daunting task.&lt;/p&gt;

&lt;p&gt;Questions start swirling in your mind:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;"Which files are essential and which can be removed?"&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;"Which packages are the largest?"&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;"Who can I report these issues to?"&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's understandable to feel overwhelmed. &lt;/p&gt;

&lt;h2&gt;
  
  
  Your new favorite tool: &lt;em&gt;pkg-size.dev&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zK7zxZO6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8xpjo750kyotmuamrnm1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zK7zxZO6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8xpjo750kyotmuamrnm1.png" alt="Screenshot of pkg-size.dev" width="800" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;em&gt;pkg-size.dev&lt;/em&gt;&lt;/center&gt;

&lt;p&gt;&lt;a href="https://pkg-size.dev"&gt;pkg-size.dev&lt;/a&gt; is a powerful online tool designed to answer these questions. It empowers JavaScript developers to examine npm packages effortlessly. It provides valuable insights into the installation size and bundle size of the packages, helping developers make informed decisions when choosing dependencies for their projects.&lt;/p&gt;

&lt;h3&gt;
  
  
  Want to see for yourself? Try it out!
&lt;/h3&gt;

&lt;p&gt;Using &lt;em&gt;pkg-size.dev&lt;/em&gt; should feel simple and familiar. Just as you would on your computer, start by typing the name of the npm package you want to examine into the terminal. Hit the Return key, and watch the magic happen. The tool will run &lt;code&gt;npm install&lt;/code&gt; on the specified package and analyze the &lt;code&gt;node_modules&lt;/code&gt; directory to get you the size of each package and the total size. It will then bundle the package with esbuild, and analyze that too.&lt;/p&gt;

&lt;p&gt;To get started, explore some popular packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://pkg-size.dev/vite"&gt;Vite&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pkg-size.dev/webpack"&gt;Webpack&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pkg-size.dev/express"&gt;Express&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pkg-size.dev/axios"&gt;Axios&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How does it work?
&lt;/h3&gt;

&lt;p&gt;The most incredible part about this tool is all of this happens right within your browser, courtesy of the amazing &lt;a href="https://webcontainers.io"&gt;WebContainers API&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;WebContainers is a new technology developed by &lt;a href="https://stackblitz.com"&gt;StackBlitz&lt;/a&gt; that allows you run Node.js in the browser. No need to set up a new project environment or deal with complex setups. Just a seamless experience right where you're most comfortable.&lt;/p&gt;

&lt;p&gt;Because of this, the website can be completely static and doesn't need a backend service. As the author, removing server &amp;amp; maintenance costs was one of the most compelling reasons for creating this tool. It's exciting that many new ideas are now possible with this technology.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features to explore
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Install size insights
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jzcZH2QV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rraj63lr78km1xb0r27o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jzcZH2QV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rraj63lr78km1xb0r27o.png" alt="Install size section of pkg-size.dev" width="800" height="691"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;em&gt;The "Install size" section for &lt;code&gt;vue&lt;/code&gt;&lt;/em&gt;&lt;/center&gt;




&lt;p&gt;Once the installation is complete, &lt;em&gt;pkg-size.dev&lt;/em&gt; presents you with an informative Install Size section. Here, you'll find a detailed breakdown of every package that was installed during the process. The insights include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The largest dependency installed.&lt;/li&gt;
&lt;li&gt;The reasons behind why each package was installed.&lt;/li&gt;
&lt;li&gt;Links to license, repository, homepage, and npm page.&lt;/li&gt;
&lt;li&gt;Whether they have CommonJS/ESM/type distributions.&lt;/li&gt;
&lt;li&gt;The different file types that make up the package.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With this comprehensive information at your fingertips, you can easily evaluate the impact each dependency has and make informed decisions.&lt;/p&gt;

&lt;p&gt;Here are some questions you might want to consider for your evaluation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Is there a package that's abnormally large?&lt;/li&gt;
&lt;li&gt;Is there a package that's installed unnecessarily?&lt;/li&gt;
&lt;li&gt;Is there a package that can benefit from ESM distribution?&lt;/li&gt;
&lt;li&gt;Is there a package unnecessarily publishing files that can be ignored?&lt;/li&gt;
&lt;li&gt;Is there a CLI package installing TypeScript types?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you come across any issues or areas for improvement, don't hesitate to report them to the project repository. Your feedback could benefit the entire community.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Bundle size exploration
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lFHCVrM8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p8pi9lgzsez4wlm4j8zn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lFHCVrM8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p8pi9lgzsez4wlm4j8zn.png" alt="Bundle size section of pkg-size.dev" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;em&gt;The "Bundle size" section for &lt;code&gt;vue&lt;/code&gt;&lt;/em&gt;&lt;/center&gt;




&lt;p&gt;In addition to the Install Size insights, &lt;em&gt;pkg-size.dev&lt;/em&gt; also offers a Bundle Size section. This feature is especially useful when you're dealing with frontend packages that you expect to be bundled together. Unlike the installation size, the bundle size is usually much smaller because it only includes code that is actually referenced in your project, and it's also minified to reduce its footprint. As a tip, the bundle size can also give you an idea of how much bloat is present in your &lt;code&gt;node_modules&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;If the bundled package has an &lt;a href="https://www.w3schools.com/js/js_modules.asp"&gt;ESM distribution (JavaScript/ECMAScript Modules)&lt;/a&gt;, you can experiment with an exciting optimization called &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Tree_shaking"&gt;"tree shaking"&lt;/a&gt; to reduce the bundle size even further. Try excluding a named import to see how many bytes it could save in the final bundle. This feature gives you the flexibility to play around with different scenarios and optimize your bundle effectively.&lt;/p&gt;

&lt;p&gt;Ready to experiment? Try these ESM packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://pkg-size.dev/chalk"&gt;Chalk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pkg-size.dev/lodash-es"&gt;lodash-es&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://pkg-size.dev/vue"&gt;Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you find a package that's including a lot of unnecessary code, and could benefit from tree shaking, you can report it to the project repository and help improve their package.&lt;/p&gt;

&lt;p&gt;To dive deeper into the bundle size, you can also download the bundle and analyze it locally using your favorite tools.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Interaction between package dependencies
&lt;/h3&gt;

&lt;p&gt;Another fascinating use-case of &lt;em&gt;pkg-size.dev&lt;/em&gt; is observing how multiple packages with shared dependencies interact with each other. By providing multiple package names and specifying their semver ranges, you can gain insights into their compatibility and spot any potential issues.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Ycp0c7ww--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nomrkanwxic38434oycx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Ycp0c7ww--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nomrkanwxic38434oycx.png" alt="Multiple packages passed into pkg-size.dev" width="800" height="200"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;em&gt;Pass in multiple packages and semver ranges to see how they interact&lt;/em&gt;&lt;/center&gt;




&lt;p&gt;For example, installing both &lt;a href="https://pkg-size.dev/esbuild%20esbuild-loader@3.0.1"&gt;&lt;code&gt;esbuild&lt;/code&gt; and &lt;code&gt;esbuild-loader@3.0.1&lt;/code&gt;&lt;/a&gt; reveals that two different versions of &lt;code&gt;esbuild&lt;/code&gt; are installed due to a mismatch in the semver ranges. This discovery could prompt maintainers to update their dependencies and release an update.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wP_wyNKl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bmfjw55yfqewbchavmg0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wP_wyNKl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bmfjw55yfqewbchavmg0.png" alt="Two versions of esbuild installed" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;center&gt;&lt;em&gt;Two different versions of esbuild installed&lt;/em&gt;&lt;/center&gt;




&lt;h2&gt;
  
  
  Have feedback or ideas?
&lt;/h2&gt;

&lt;p&gt;I'm committed to making &lt;em&gt;pkg-size.dev&lt;/em&gt; a tool that gives you super powers.&lt;/p&gt;

&lt;p&gt;If you have any feedback, feature requests, or bug reports, don't hesitate to share them in the &lt;a href="https://github.com/privatenumber/pkg-size.dev/issues"&gt;GitHub repository&lt;/a&gt;. Your contributions will help shape the future of this tool.&lt;/p&gt;

&lt;h3&gt;
  
  
  Share your insights
&lt;/h3&gt;

&lt;p&gt;As you dive into the npm ecosystem using &lt;em&gt;pkg-size.dev&lt;/em&gt;, you're bound to discover interesting insights and valuable learnings. Feel free to share your findings in &lt;a href="https://github.com/privatenumber/pkg-size.dev/discussions"&gt;GitHub Discussions&lt;/a&gt;. These discussions could spark more ideas for features and ways to gain insight.&lt;/p&gt;

&lt;h3&gt;
  
  
  Show your support 💞
&lt;/h3&gt;

&lt;p&gt;If you found &lt;em&gt;pkg-size.dev&lt;/em&gt; to be useful and save you a lot of time, supporting the project is a fantastic way to show appreciation. If you find the tool useful, please &lt;a href="https://github.com/sponsors/privatenumber"&gt;consider sponsoring it on GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Happy analyzing and exploring the npm world with &lt;a href="https://pkg-size.dev"&gt;pkg-size.dev&lt;/a&gt;! ✌️&lt;/p&gt;

</description>
      <category>npm</category>
      <category>node</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
    <item>
      <title>4 reasons to avoid using `npm link`</title>
      <dc:creator>Hiroki Osame</dc:creator>
      <pubDate>Mon, 25 Apr 2022 18:15:54 +0000</pubDate>
      <link>https://dev.to/privatenumber/4-reasons-to-avoid-using-npm-link-5d03</link>
      <guid>https://dev.to/privatenumber/4-reasons-to-avoid-using-npm-link-5d03</guid>
      <description>&lt;h2&gt;
  
  
  TL; DR
&lt;/h2&gt;

&lt;p&gt;Instead of using &lt;code&gt;npm link&lt;/code&gt;, use &lt;code&gt;npm install&lt;/code&gt; or &lt;code&gt;npx link&lt;/code&gt; to symlink a local package as a dependency:&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;npx &lt;span class="nb"&gt;link&lt;/span&gt; &amp;lt;package-path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/privatenumber/link"&gt;&lt;code&gt;npx link&lt;/code&gt;&lt;/a&gt; is a tool I developed as a safer and more predictable alternative to &lt;code&gt;npm link&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Avoid using &lt;code&gt;npm link&lt;/code&gt; because of the following footguns:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Error-prone with multiple Node.js versions&lt;/li&gt;
&lt;li&gt;No fail-case and unexpected fallback to npm registry&lt;/li&gt;
&lt;li&gt;Unexpected binary installation&lt;/li&gt;
&lt;li&gt;Unexpected link removal&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What's &lt;code&gt;npm link&lt;/code&gt;?
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.npmjs.com/cli/v8/commands/npm-link"&gt;&lt;code&gt;npm link&lt;/code&gt;&lt;/a&gt; is a command-line tool for &lt;a href="https://en.wikipedia.org/wiki/Symbolic_link"&gt;symlinking&lt;/a&gt; a local package as a dependency during development. It is commonly used for testing packages before publishing them.&lt;/p&gt;

&lt;p&gt;Read more about it in the &lt;a href="https://docs.npmjs.com/cli/v8/commands/npm-link"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Usage
&lt;/h3&gt;

&lt;p&gt;Given the following packages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;my-library&lt;/code&gt;: an npm package that you want to test in another package as a dependency.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; property in &lt;code&gt;my-library/package.json&lt;/code&gt; should be &lt;code&gt;my-library&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;my-application&lt;/code&gt;: the package/project you want to test in&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's how you would link them:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Registration&lt;/strong&gt; (Global installation)&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npm link&lt;/code&gt; in &lt;code&gt;my-library&lt;/code&gt; to install it globally, making it possible to link &lt;code&gt;my-library&lt;/code&gt; to any local project. Note: this is the same thing as running &lt;code&gt;npm install --global&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&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;&lt;span class="nb"&gt;cd&lt;/span&gt; ./my-library
&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;link&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Run &lt;code&gt;npm link my-library&lt;/code&gt; in &lt;code&gt;my-application&lt;/code&gt; to link it:&lt;br&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&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;&lt;span class="nb"&gt;cd&lt;/span&gt; ./my-application
&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;link &lt;/span&gt;my-library
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Shortcut
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;npm link &amp;lt;package-path&amp;gt;&lt;/code&gt; is a shortcut to automate the two steps by simply passing in the package path.&lt;/p&gt;

&lt;p&gt;Using the example above:&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;&lt;span class="nb"&gt;cd&lt;/span&gt; ./my-application
&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;link&lt;/span&gt; ../my-library
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shortcut approach is much easier to use and is less error-prone because it's a single command that requires an explicit path to the package to link.&lt;/p&gt;

&lt;h2&gt;
  
  
  4 footguns of &lt;code&gt;npm link&lt;/code&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  ​1. Multiple Node.js versions
&lt;/h3&gt;

&lt;p&gt;If your environment has multiple Node.js versions using a manager like &lt;a href="http://nvm.sh/"&gt;nvm&lt;/a&gt;, both &lt;code&gt;npm link&lt;/code&gt; commands must be run using the same version.&lt;/p&gt;

&lt;p&gt;As explained above, the first step of &lt;code&gt;npm link&lt;/code&gt; is installing the package globally. Since each version of Node.js has its own global package registry, lookups will fail if different versions are used.&lt;/p&gt;

&lt;p&gt;You can check if the global package registry is scoped to the Node.js version with the following command. If the Node.js version is in the path, the global package registry is scoped:&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;npm root &lt;span class="nt"&gt;-g&lt;/span&gt;
~/.nvm/versions/node/v14.16.1/lib/node_modules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When working on multiple packages in separate terminal sessions, it's very easy to overlook the Node.js version. The version discrepancy can be especially hard to notice since &lt;code&gt;npm link&lt;/code&gt; doesn't error when it's unable to find the local package to link, which is discussed in the next section.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pro tip:&lt;/strong&gt; Add the &lt;a href="https://github.com/nvm-sh/nvm/blob/2c0c34f/README.md#deeper-shell-integration"&gt;recommended shell integration&lt;/a&gt; to automatically use the appropriate Node.js version when entering a directory with a &lt;code&gt;.nvmrc&lt;/code&gt; file.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ​2. Non-existent fail-case
&lt;/h3&gt;

&lt;p&gt;Try running &lt;code&gt;npm link a&lt;/code&gt; in a package.&lt;/p&gt;

&lt;p&gt;It will succeed despite never registering package &lt;code&gt;a&lt;/code&gt; to be linkable before:&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;npm &lt;span class="nb"&gt;link &lt;/span&gt;a
~/my-package/node_modules/a -&amp;gt; ~/.nvm/versions/node/v14.16.1/lib/node_modules/a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is because when &lt;code&gt;npm link&lt;/code&gt; can't find package &lt;code&gt;a&lt;/code&gt; as a global package, it installs it globally from &lt;a href="https://www.npmjs.com/package/a"&gt;the npm registry&lt;/a&gt; and creates a symlink to it.&lt;/p&gt;

&lt;p&gt;It only fails when the package is also not found on the remote registry:&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;npm &lt;span class="nb"&gt;link &lt;/span&gt;non-existent-package
npm ERR! code E404
npm ERR! 404 Not Found - GET https://registry.npmjs.org/non-existent-package - Not found
npm ERR! 404 
npm ERR! 404  &lt;span class="s1"&gt;'non-existent-package@*'&lt;/span&gt; is not &lt;span class="k"&gt;in &lt;/span&gt;this registry.
npm ERR! 404 You should bug the author to publish it &lt;span class="o"&gt;(&lt;/span&gt;or use the name yourself!&lt;span class="o"&gt;)&lt;/span&gt;
npm ERR! 404 
npm ERR! 404 Note that you can also &lt;span class="nb"&gt;install &lt;/span&gt;from a
npm ERR! 404 tarball, folder, http url, or git url.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To tell if the link &lt;em&gt;actually&lt;/em&gt; succeeded, you can check if the output has two arrows (&lt;code&gt;-&amp;gt;&lt;/code&gt;). (Notice how the false-positive above only has one arrow.) Two arrows means it created a symlink to the global package, which then points to the local package:&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;npm &lt;span class="nb"&gt;link &lt;/span&gt;my-linked-package
~/my-package/node_modules/my-linked-package -&amp;gt; ~/.nvm/versions/node/v14.16.1/lib/node_modules/my-linked-package -&amp;gt; ~/my-linked-package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This check only works in npm v6. Unfortunately, starting in npm v7, the symlink paths are no longer logged. Looking at the output, it's impossible to determine if linking the local package succeeded, or if an unintended package was accidentally installed and linked:&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;npm &lt;span class="nb"&gt;link &lt;/span&gt;a

up to &lt;span class="nb"&gt;date&lt;/span&gt;, audited 3 packages &lt;span class="k"&gt;in &lt;/span&gt;671ms

found 0 vulnerabilities
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To confirm the package was successfully linked, you can use &lt;a href="https://www.gnu.org/software/coreutils/realpath"&gt;&lt;code&gt;realpath&lt;/code&gt;&lt;/a&gt; to verify the symlink path:&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;&lt;span class="nb"&gt;realpath &lt;/span&gt;node_modules/package-name
~/my-linked-package
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The lack of a proper fail case makes using &lt;code&gt;npm link&lt;/code&gt; a confusing and frail process. Especially when compounded with having multiple Node.js versions.&lt;/p&gt;

&lt;h3&gt;
  
  
  ​3. Unexpected binary installation
&lt;/h3&gt;

&lt;p&gt;The first step of &lt;code&gt;npm link&lt;/code&gt; installs the package &lt;em&gt;globally&lt;/em&gt;. This happens in the shortcut as well, because it just automates the two steps.&lt;/p&gt;

&lt;p&gt;Global package installation (&lt;a href="https://docs.npmjs.com/cli/v8/commands/npm-install#global"&gt;&lt;code&gt;npm install --global ...&lt;/code&gt;&lt;/a&gt;) is a type of package installation used to make binaries available as a system-wide CLI command. So, if your package has a &lt;a href="https://docs.npmjs.com/cli/v7/configuring-npm/package-json#bin"&gt;&lt;code&gt;bin&lt;/code&gt; field&lt;/a&gt;, &lt;code&gt;npm link&lt;/code&gt;ing it will make it available as a CLI command.&lt;/p&gt;

&lt;p&gt;Considering &lt;code&gt;npm link&lt;/code&gt; is a tool for testing a package in development, global binary installation can be an unexpected and undesired side-effect. The implications of this unexpected behavior can be quite serious given packages can declare binaries with &lt;a href="https://docs.npmjs.com/cli/v7/configuring-npm/package-json#:~:text=%22bin%22%3A%20%7B-,%22my%2Dprogram%22,-%3A%20%22./path/to/program"&gt;arbitrary names&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this example package, an arbitrary binary name &lt;code&gt;random-command&lt;/code&gt; is specified in the &lt;code&gt;package.json&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"my-package"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"bin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"random-command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bin.js"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;npm link&lt;/code&gt; installs binary &lt;code&gt;random-command&lt;/code&gt;:&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;random-command
zsh: &lt;span class="nb"&gt;command &lt;/span&gt;not found: random-command

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-package &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;link
&lt;/span&gt;added 1 package, and audited 3 packages &lt;span class="k"&gt;in &lt;/span&gt;548ms

found 0 vulnerabilities

&lt;span class="nv"&gt;$ &lt;/span&gt;random-command
Suddenly works!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Global install can also override existing binaries depending on your &lt;a href="https://linuxhint.com/path_in_bash/"&gt;&lt;code&gt;PATH&lt;/code&gt; configuration&lt;/a&gt;—the variable of paths the shell uses to lookup commands from. If you're using &lt;a href="http://nvm.sh/"&gt;nvm&lt;/a&gt;, your configuration is likely &lt;a href="https://github.com/nvm-sh/nvm/issues/2140"&gt;susceptible to this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this example, I override the binary &lt;code&gt;cat&lt;/code&gt;, a &lt;a href="https://en.wikipedia.org/wiki/Cat_(Unix)"&gt;standard Unix utility&lt;/a&gt;:&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;&lt;span class="nb"&gt;type cat
cat &lt;/span&gt;is /bin/cat

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;my-package &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; npm &lt;span class="nb"&gt;link
&lt;/span&gt;added 1 package, and audited 3 packages &lt;span class="k"&gt;in &lt;/span&gt;230ms

found 0 vulnerabilities

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;hash &lt;/span&gt;cash
&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;type cat
cat &lt;/span&gt;is ~/.nvm/versions/node/v16.14.0/bin/cat
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In regards to software installation, these risks are prevalent in every software manager and aren't considered too dangerous from a security perspective.&lt;/p&gt;

&lt;p&gt;However, &lt;code&gt;npm link&lt;/code&gt; is not a package installer. It's supposed to be a simple tool to setup symlinks for development. It's worth pausing to reflect on how unexpected this behavior is, and what mistakes it could lead to.&lt;/p&gt;

&lt;p&gt;By the way, if you ran &lt;code&gt;npm link a&lt;/code&gt; in the prior section, a binary &lt;code&gt;a&lt;/code&gt; has been installed to your system. You would think &lt;code&gt;npm unlink a&lt;/code&gt; will uninstall it, but it only removes the local link and not the globally installed binaries.&lt;/p&gt;

&lt;p&gt;Uninstall a global package and its binaries with:&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;npm uninstall &lt;span class="nt"&gt;--global&lt;/span&gt; a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  ​4. Unexpected link removal
&lt;/h3&gt;

&lt;p&gt;When linking multiple packages, previously linked packages are removed. This behavior is a regression introduced in npm v7.&lt;/p&gt;

&lt;p&gt;In this example, &lt;code&gt;pkg-a&lt;/code&gt; is linked and confirmed to be in &lt;code&gt;node_modules&lt;/code&gt;. However, after linking a second package &lt;code&gt;pkg-b&lt;/code&gt;, &lt;code&gt;pkg-a&lt;/code&gt; is no longer in &lt;code&gt;node_modules&lt;/code&gt;:&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;npm &lt;span class="nb"&gt;link&lt;/span&gt; ../pkg-a
added 1 package, and audited 5 packages &lt;span class="k"&gt;in &lt;/span&gt;684ms
found 0 vulnerabilities

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;node_modules 
pkg-a

&lt;span class="nv"&gt;$ &lt;/span&gt;npm &lt;span class="nb"&gt;link&lt;/span&gt; ../pkg-b
added 1 package, removed 1 package, and audited 5 packages &lt;span class="k"&gt;in &lt;/span&gt;703ms
found 0 vulnerabilities

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;node_modules  
pkg-b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Removing previous links can be unexpected and confusing when working with multiple packages. Often times, after linking the second package, we'd continue to run code expecting the links to persist.&lt;/p&gt;

&lt;p&gt;To link multiple packages, you must pass in all package paths into one command:&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;npm &lt;span class="nb"&gt;link&lt;/span&gt; ../pkg-a ../pkg-b
added 1 package, and audited 6 packages &lt;span class="k"&gt;in &lt;/span&gt;645ms
found 0 vulnerabilities

&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;node_modules 
pkg-a pkg-b
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this &lt;em&gt;works&lt;/em&gt;, it's not a great developer experience. In development, we don't always know ahead of time all the packages that need to be linked. Or keep track of the previously linked packages.&lt;/p&gt;

&lt;p&gt;This confusing behavior compounds to the poor usability and predictability of &lt;code&gt;npm link&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Potential for accidents
&lt;/h3&gt;

&lt;p&gt;As with any popular package registry, npm has a diverse collection with no standard for quality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.npmjs.com/reporting-malware-in-an-npm-package"&gt;npm removes malicious packages&lt;/a&gt;, but risks mentioned above are not limited to attacks. When it's unclear whether the right package was installed, there is always potential for accidents.&lt;/p&gt;

&lt;p&gt;Many packages on npm are designed to make changes to the file-system, such as &lt;a href="https://www.npmjs.com/package/rimraf"&gt;rimraf&lt;/a&gt; or a code linter. In an accident, the consequences of running file-system altering code can be detrimental.&lt;/p&gt;

&lt;p&gt;Installing the wrong package is possible with &lt;code&gt;npm install&lt;/code&gt; as well, but the risks are higher with &lt;code&gt;npm link&lt;/code&gt; when the footguns above come together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Package names can collide.&lt;/strong&gt; It's possible to link a local package with a name that's on the &lt;a href="https://www.npmjs.com/"&gt;npm registry&lt;/a&gt;. This can happen when developing and testing a new or private package before realizing the name is already taken.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;No local resolution error.&lt;/strong&gt; If the package being linked can't be locally resolved, it will get resolved from the npm registry. If a package with the same name is found, an unexpected package can get globally installed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Binaries are installed.&lt;/strong&gt; If the wrong package is installed, it's unintuitive that binaries get installed and to realize it needs to be uninstalled globally. This leaves unexpected binaries to be left installed and accidentally invoked.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use &lt;code&gt;npm install&lt;/code&gt; instead
&lt;/h2&gt;

&lt;p&gt;A better alternative to &lt;code&gt;npm link&lt;/code&gt; is &lt;code&gt;npm install&lt;/code&gt; using a package path:&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;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-save&lt;/span&gt; &amp;lt;package-path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This creates a symlink to the package without installing it globally. This behavior is probably closer to what most people expect from &lt;code&gt;npm link&lt;/code&gt;. The &lt;code&gt;--no-save&lt;/code&gt; flag is to prevent the package path from getting saved in &lt;code&gt;package.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;However, this command still comes with a drawback. Like &lt;code&gt;npm link&lt;/code&gt;, running &lt;code&gt;npm install&lt;/code&gt; multiple times will remove previous links. To link multiple packages, pass in the package paths as arguments:&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;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-save&lt;/span&gt; &amp;lt;package-path-a&amp;gt; &amp;lt;package-path-b&amp;gt; ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Introducing &lt;code&gt;npx link&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;An even better alternative to &lt;code&gt;npm link&lt;/code&gt; is &lt;a href="https://github.com/privatenumber/link"&gt;&lt;code&gt;npx link&lt;/code&gt;&lt;/a&gt;, a tiny tool I developed to tackle the problems addressed in this post.&lt;/p&gt;

&lt;p&gt;Using the command is simple:&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;npx &lt;span class="nb"&gt;link&lt;/span&gt; &amp;lt;package-path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/privatenumber/link"&gt;&lt;code&gt;npx link&lt;/code&gt;&lt;/a&gt; doesn't globally install the linked package or its binaries. It doesn't remove previous links. And it works across different versions of Node.js because it makes direct symlinks. It also has a clear fail-state when it can't resolve the package path.&lt;/p&gt;

&lt;p&gt;If you want to use binaries from the package, they will only be installed locally and will only be executable with &lt;a href="https://docs.npmjs.com/cli/v8/commands/npx"&gt;npx&lt;/a&gt; or via &lt;a href="https://docs.npmjs.com/cli/v8/using-npm/scripts"&gt;package scripts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As an added benefit for the community, package linking will still work for those who accidentally type in &lt;code&gt;npx link&lt;/code&gt; instead of &lt;code&gt;npm link&lt;/code&gt;!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>discuss</category>
      <category>security</category>
    </item>
    <item>
      <title>4 tips from my SWE promotion at Square</title>
      <dc:creator>Hiroki Osame</dc:creator>
      <pubDate>Wed, 13 Apr 2022 21:17:36 +0000</pubDate>
      <link>https://dev.to/privatenumber/4-tips-from-my-swe-promotion-at-square-ihf</link>
      <guid>https://dev.to/privatenumber/4-tips-from-my-swe-promotion-at-square-ihf</guid>
      <description>&lt;p&gt;I'm a Software Engineer at &lt;a href="https://squareup.com/"&gt;Square&lt;/a&gt;, and I was promoted to a &lt;a href="https://assets.ctfassets.net/1wryd5vd9xez/6bDnTwb4H7bfiFvg55ldRR/b1cb8514f0afd0a4050991d35ccbac03/Square_Software_Engineering_Career_Ladder.pdf"&gt;Level 6 (&lt;em&gt;team leader&lt;/em&gt;) Individual Contributor (IC)&lt;/a&gt; two years ago.&lt;/p&gt;

&lt;p&gt;I didn't have a chance to reflect on my learnings, but a colleague recently reached out regarding my promotion packet. He was working on his application and wanted to see mine as an example and get some pointers.&lt;/p&gt;

&lt;p&gt;I'm publicizing the advice I shared with him in hopes that others who are also applying for IC promotions can find it helpful.&lt;/p&gt;

&lt;p&gt;Here are 4 tips I learned from my promotion application.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Prioritize collaboration over personal achievement
&lt;/h3&gt;

&lt;p&gt;It took me two tries to get the L6 promotion.&lt;/p&gt;

&lt;p&gt;One of the reasons my first application was rejected was because I showcased an incident where I independently "saved the day". I helped my team meet a Monday deadline by working over the weekend to fix a problem I discovered late Friday evening.&lt;/p&gt;

&lt;p&gt;This came as a surprise to me because I felt like I was demonstrating competence, determination, and ability to carry the team.&lt;/p&gt;

&lt;p&gt;However, the promotion committee argued that I was enabling poor work-life balance by setting a precedent for others to also work overtime. This was a project underestimation issue, and I shouldn't have carried the consequences independently.&lt;/p&gt;

&lt;p&gt;Given that L6 is &lt;em&gt;a team leader&lt;/em&gt;, it was important I operated at a higher level of awareness and leadership. Instead of acting alone, I should have discussed with the team so the deliverables and target dates could be adjusted and not disrupt anyone's work-life balance.&lt;/p&gt;

&lt;p&gt;To prepare for my next promotion packet, I put collaboration work before independent contributions and sought opportunities to lead and raise others.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Collect testimonials from everyone you work with
&lt;/h3&gt;

&lt;p&gt;The promotion packet has a section to request peer feedback from engineers at the target level I was applying to. In my case, L6 engineers. This section was tough for me to complete because I hadn't worked with many L6s. Not being able to ask most of my colleagues for feedback made me feel like I was at a disadvantage.&lt;/p&gt;

&lt;p&gt;After struggling with this, I eventually came to the realization nothing was stopping me from including quotes &amp;amp; testimonials from others outside of the peer feedback section.&lt;/p&gt;

&lt;p&gt;I started reaching out to everyone I worked closely with: L5 engineers, product managers, designers, and engineer managers. And I asked them for a testimonial on their experience working with me. My promotion packet was scattered with quotes from my peers in varying roles, adding lots of colors and boasting collaboration.&lt;/p&gt;

&lt;p&gt;As an added benefit, personally reaching out for feedback allowed me to have more control over the process. The official feedback had to be solicited by my manager through a Google Forms survey, and sometimes, this results in unengaging or irrelevant feedback. Reaching out directly created opportunities to follow up for details/examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Share your Hype Doc when soliciting feedback
&lt;/h3&gt;

&lt;p&gt;People don't often remember your contributions.&lt;/p&gt;

&lt;p&gt;This is understandable given I struggled to remember my own as I put together my promotion packet. And when peer reviewers don't remember, they dread writing your feedback because it takes them a lot of work to revisit old documents and conversations. As a result, they might end up submitting low-quality feedback near the deadline.&lt;/p&gt;

&lt;p&gt;To make it easy for anyone providing me feedback, I published my &lt;a href="https://medium.com/square-corner-blog/you-are-your-own-best-hype-person-cf1e3a83c0c2"&gt;Hype Doc&lt;/a&gt; internally—a document of my accomplishments to track my growth. I made it into a website and hosted it on GitHub Pages, but a scrappy Google Doc with bullet points will suffice. The point of having it hosted online is to reduce friction for the reviewer to remember, learn, and talk about your work. Try to write less, make it skimmable, and prefer showing over explaining (via links and screenshots). I linked my Hype Doc everywhere, even in my Slack &amp;amp; GitHub statuses.&lt;/p&gt;

&lt;p&gt;Making my contributions easily accessible helped me get insightful and relevant feedback in a timely manner.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Develop documentation habits
&lt;/h3&gt;

&lt;p&gt;I struggled to find high-quality examples when trying to find links to demonstrate my work.&lt;/p&gt;

&lt;p&gt;Collaboration often happened on temporary and unlinkable mediums like instant messaging or meetings. And the links I found had no description and required work to understand when linking them was supposed to make it easier. Worse case, they made me look difficult to work with.&lt;/p&gt;

&lt;p&gt;I felt I missed a lot of opportunities at the cost of a minute to document them.&lt;/p&gt;

&lt;p&gt;This frustration inspired me to adopt better habits that help me document my work with little effort:&lt;/p&gt;

&lt;h4&gt;
  
  
  Improve transparency &amp;amp; discoverability
&lt;/h4&gt;

&lt;p&gt;I started moving discussions from private to public platforms.&lt;/p&gt;

&lt;p&gt;When appropriate, I moved conversations away from direct messaging, email, and meetings. Instead, I started encouraging conversations on JIRA tickets, GitHub issues/discussions, and Google Group threads.&lt;/p&gt;

&lt;p&gt;As a result, my conversations and contributions became preserved, discoverable, and linkable.&lt;/p&gt;

&lt;h4&gt;
  
  
  Improve readability
&lt;/h4&gt;

&lt;p&gt;I started to broaden my target audience in my writing and paid extra attention to spelling, grammar, and formatting. Whenever possible, I would add links, screenshots, and context.&lt;/p&gt;

&lt;p&gt;To write more inclusively, I adopted a great tip to think of the tools used by non-English speakers and people with disabilities: Are your sentences simple enough for Google Translate? Can your spelling and punctuation be dictated by a screen reader?&lt;/p&gt;

&lt;p&gt;I also generally avoid slang or niche references (eg. jokes) as they can confuse outside participants.&lt;/p&gt;

&lt;p&gt;These practices helped my writing become more accessible and easier to read. And as a bonus, my contributions looked credible and started to get referenced by others.&lt;/p&gt;

&lt;h4&gt;
  
  
  Improve skimmability
&lt;/h4&gt;

&lt;p&gt;I started to adopt templates and structure to my writing to make them easier to skim.&lt;/p&gt;

&lt;p&gt;For general writing, I adopted the &lt;a href="https://medium.com/lessons-from-mckinsey/the-pyramid-principle-f0885dd3c5c7"&gt;Pyramid Principle&lt;/a&gt;—a technique to get my point across faster.&lt;/p&gt;

&lt;p&gt;For commit messages, I adopted &lt;a href="https://www.conventionalcommits.org/"&gt;Conventional Commits&lt;/a&gt;—a convention for creating an explicit commit history.&lt;/p&gt;

&lt;p&gt;For pull requests, I fill out "Problem", "Changes", and optionally "Other info".&lt;/p&gt;

&lt;p&gt;As a result, the documentation I wrote was not only faster to read but also faster to write.&lt;/p&gt;

&lt;h2&gt;
  
  
  Parting thoughts
&lt;/h2&gt;

&lt;p&gt;These tips helped me get the most out of my work to showcase in my promotion packet.&lt;/p&gt;

&lt;p&gt;Interestingly, I also found them to have a real impact on me as an engineer. They helped me communicate better, collaborate more, and expand my reach.&lt;/p&gt;

&lt;p&gt;After all, the engineering ladder is supposed to reflect your competence as an impactful engineer.&lt;/p&gt;

&lt;p&gt;I hope you find these tips helpful to your growth as well.&lt;/p&gt;

&lt;p&gt;Good luck on your promotion!&lt;/p&gt;

</description>
      <category>career</category>
      <category>discuss</category>
      <category>motivation</category>
      <category>writing</category>
    </item>
  </channel>
</rss>
