<?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: Manuel Micu</title>
    <description>The latest articles on DEV Community by Manuel Micu (@manu4216).</description>
    <link>https://dev.to/manu4216</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%2F181076%2F88538772-64c4-4f95-93b7-631f8bf4fe60.jpg</url>
      <title>DEV Community: Manuel Micu</title>
      <link>https://dev.to/manu4216</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/manu4216"/>
    <language>en</language>
    <item>
      <title>Avoiding CSS style collisions when building a UI widget</title>
      <dc:creator>Manuel Micu</dc:creator>
      <pubDate>Fri, 01 Jul 2022 01:06:15 +0000</pubDate>
      <link>https://dev.to/manu4216/avoiding-css-style-collisions-when-building-a-ui-widget-2633</link>
      <guid>https://dev.to/manu4216/avoiding-css-style-collisions-when-building-a-ui-widget-2633</guid>
      <description>&lt;p&gt;Use case: you're tasked with developing a UI widget, that can be used in any integrator webpage. &lt;/p&gt;

&lt;p&gt;Classical examples: Google Maps, chat widget. &lt;/p&gt;

&lt;p&gt;Problem: some integrators have conflicting requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Make sure there is no style collision between the integrator-specific style and your widget style&lt;/li&gt;
&lt;li&gt;Allow the widget to be customised with integrator-specific custom style&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The bad approach
&lt;/h1&gt;

&lt;p&gt;First, let's start with the simple, but very risky approach. You can have the widget and the integrator style side-by-side, without anything in place to create any isolation, and &lt;em&gt;hope&lt;/em&gt; it will work. However, in reality, there can be a wide variety of CSS style conflicts. &lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSS selectors of the integrator can have higher selectivity than the ones used in the widget (example: &lt;code&gt;#root .button&lt;/code&gt; &amp;gt; &lt;code&gt;.button&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;common CSS selectors (such as &lt;code&gt;.root&lt;/code&gt;, &lt;code&gt;.button&lt;/code&gt;) might be used by both the integrator and the widget code, without being aware of each-other&lt;/li&gt;
&lt;li&gt;global style can pollute elements in either direction (example: &lt;code&gt;*&lt;/code&gt; selector used in the widget or integrator styles)&lt;/li&gt;
&lt;li&gt;wide-impact &lt;em&gt;element&lt;/em&gt; selectors (example: &lt;code&gt;div&lt;/code&gt;, &lt;code&gt;img&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;!important&lt;/code&gt; (used by the integrator own source code, or part of some third party library outside their control)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To accommodate the 2 requirements of style isolation AND customisation options, here are a few aspects to consider. &lt;/p&gt;

&lt;h1&gt;
  
  
  Style isolation level
&lt;/h1&gt;

&lt;p&gt;Technical solution available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;side-by-side integrator/widget code&lt;/strong&gt;. &lt;em&gt;A few CSS tricks will be needed to avoid unwanted style conflicts. This approach will be looked into closer bellow.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;iframe&lt;/strong&gt; &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;shadow DOM&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Style customisation level
&lt;/h1&gt;

&lt;p&gt;This is actually a range, that can go from:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Little to no customisation&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Specific allowed customisation&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Anything can be customised&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Technical solutions available for allowing style customisation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;shared CSS (when side-by-side integrator/widget)&lt;/li&gt;
&lt;li&gt;definition of CSS variables&lt;/li&gt;
&lt;li&gt;style passed to the widget, as a configuration, or a file: 

&lt;ul&gt;
&lt;li&gt;passed in-process at initialisation&lt;/li&gt;
&lt;li&gt;passed using iframe &lt;code&gt;postMessage&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;passed via HTTP retrieval, based on a unique integrator id&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;complete customisation, by allowing the integrator to fork your widget source code (if your widget is open source)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;: Depending on your needs and choice, the best solution will not be the same for everyone.&lt;/p&gt;

&lt;p&gt;Let's see a few of these approaches in more detail in the next sections.  &lt;/p&gt;

&lt;p&gt;&lt;em&gt;NOTE&lt;/em&gt;: There is a code sandbox at the end.&lt;/p&gt;

&lt;h1&gt;
  
  
  Approach 1: wrap your widget with an &lt;code&gt;iframe&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;This solution is very effective, since it creates a new context. CSS style outside the iframe will not influence your widget.&lt;/p&gt;

&lt;p&gt;You then have many options to define your customisation interface, while keeping the rest of the widget style immune to style collisions.&lt;/p&gt;

&lt;p&gt;Important remark: there are 2 ways to add an iframe to your widget:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;add it yourself, inside the widget code. This applies it to all the integrators. &lt;/li&gt;
&lt;li&gt;tell the integrators to add the iframe around the widget. This way, the integrator creates an isolation between their style, and the widget style. They can then apply custom CSS, the same way as the side-by-side approach:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"widgetWrapperToOverrideWidgetStyle"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"widgetRoot"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Injected widget&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach is one of the preferred ones when you want to avoid style collisions at all cost. &lt;/p&gt;

&lt;h1&gt;
  
  
  Approach 2: Side-by-side integrator/widget, with &lt;code&gt;CSS unset&lt;/code&gt; isolation
&lt;/h1&gt;

&lt;p&gt;This solution may be enough in many cases. But it comes with some drawbacks to the widget:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it resets the browser defaults (example a &lt;code&gt;div&lt;/code&gt; will no longer have &lt;code&gt;display: block&lt;/code&gt;, but &lt;code&gt;display: inline&lt;/code&gt;). 
So extra style is required to restore that. In theory, many properties may be impacted. In my experience, setting &lt;code&gt;display: block&lt;/code&gt; is enough.&lt;/li&gt;
&lt;li&gt;some unintended style override is still possible. This happens if high selectivity CSS is used on the integrator side, such as &lt;code&gt;!important&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, this last point is also an advantage, since it allows the integrator to customise anything, if needed.&lt;/p&gt;

&lt;p&gt;Useful CSS concepts related to this approach:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/all"&gt;all&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/unset"&gt;unset&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/inheritance#inherited_properties"&gt;inherited properties&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to make this work well, you need to be careful not to pollute the style of the integrator elements. This can be avoided with discipline in the kind of CSS the widget uses.&lt;/p&gt;

&lt;p&gt;What you need to avoid:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;*&lt;/code&gt; selector &lt;/li&gt;
&lt;li&gt;element selectors (examples: &lt;code&gt;div&lt;/code&gt;, &lt;code&gt;h1&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;selectors with low specificity, using common names (example: &lt;code&gt;.button&lt;/code&gt;). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All these can be made safe by using them within a higher selectivity selector, such as: &lt;code&gt;#widgetRoot *&lt;/code&gt;, &lt;code&gt;#widgetRoot div&lt;/code&gt;, &lt;code&gt;#widgetRoot .button&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Extract of the implementation of this approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="c"&gt;/* this is the main trick */&lt;/span&gt;
&lt;span class="nc"&gt;.widgetRoot&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;all&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;unset&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;/* Compensate unwanted effect of `unset` */&lt;/span&gt;
&lt;span class="nc"&gt;.widgetRoot&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.widgetRoot&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;.widgetRoot&lt;/span&gt; &lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;
&lt;span class="nc"&gt;.widgetRoot&lt;/span&gt; &lt;span class="nt"&gt;h1&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;block&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the CSS trick described above, you now have more isolation between the integrator style and the widget style. Integrator style should not, by default, have unexpected impact on the widget style.&lt;/p&gt;

&lt;p&gt;It is still possible to customise the widget style, but it requires deliberate intention, since it requires high selectivity (for instance use of id selector). Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="nf"&gt;#integratorRoot&lt;/span&gt; &lt;span class="nc"&gt;.widgetRoot&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="py"&gt;--color-theme&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;pink&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the selector approach used inside your widget, there are 2 scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;stable widget selectors (example &lt;code&gt;.widgetTitle&lt;/code&gt;, &lt;code&gt;.widgetFooter&lt;/code&gt;). This does allow the integrator to reliably override the style of these elements. &lt;/li&gt;
&lt;li&gt;unstable widget selectors (example: generated with file content hash, &lt;code&gt;.rDhk_jr_i8&lt;/code&gt;). This can be done on purpose, to signal the integrator that they should not attempt to customise other things other than the customisation interface that you defined, such as your CSS variables). &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In conclusion, this solution making use of &lt;code&gt;all: unset&lt;/code&gt; may work well in some cases. But because of its &lt;em&gt;soft&lt;/em&gt; type of boundary, you may still encounter some issues with accidental CSS style overrides. And, you will need to write more CSS to compensate for the &lt;code&gt;unset&lt;/code&gt; effect, and avoid CSS conflicts.&lt;/p&gt;

&lt;p&gt;So if you want to play safe, then &lt;em&gt;harder&lt;/em&gt;  isolation context approaches are probably preferable.&lt;/p&gt;

&lt;h1&gt;
  
  
  Approach 3: Shadow DOM
&lt;/h1&gt;

&lt;p&gt;I don't have experience with this approach, and I didn't look into it at this point[&lt;em&gt;time constraint&lt;/em&gt;]. However, the described use-case is probably well-suited for what shadow DOM has to offer (style encapsulation).&lt;/p&gt;

&lt;p&gt;I will leave it to you to read more about it: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM"&gt;https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Code demo
&lt;/h1&gt;

&lt;p&gt;I implemented a quick demonstration for Approach 1 and 2 side-by-side. Feel free to explore the code.&lt;br&gt;
&lt;iframe src="https://codesandbox.io/embed/dazzling-sky-5qqcfv"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimers&lt;/em&gt;: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The shared demo does not contain production-quality code. &lt;/li&gt;
&lt;li&gt;The approaches that are listed here don't represent an exhaustive list of all possible approaches. Feel free to suggest others that I missed.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>css</category>
    </item>
    <item>
      <title>Visualization of route navigation in a React app</title>
      <dc:creator>Manuel Micu</dc:creator>
      <pubDate>Sun, 19 Sep 2021 23:00:59 +0000</pubDate>
      <link>https://dev.to/manu4216/visualization-of-route-navigation-in-a-react-app-35lg</link>
      <guid>https://dev.to/manu4216/visualization-of-route-navigation-in-a-react-app-35lg</guid>
      <description>&lt;p&gt;This post describes how you can build your own visualization of the navigation inside a React web application. &lt;/p&gt;

&lt;p&gt;Such visualization can transform a complex user journey into a more easy to understand, interactive network graph.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context in my company
&lt;/h2&gt;

&lt;p&gt;Tech stack: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;react SPA&lt;/li&gt;
&lt;li&gt;react-router&lt;/li&gt;
&lt;li&gt;30+ screens&lt;/li&gt;
&lt;li&gt;screens grouped in multiple bundles, loaded only when/if needed&lt;/li&gt;
&lt;li&gt;folder structure: &lt;code&gt;src/screens/&amp;lt;bundle&amp;gt;/&amp;lt;screen&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Problem
&lt;/h2&gt;

&lt;p&gt;No single place to view all these routes, that would allow new developers to quickly understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how the screens are split into bundles&lt;/li&gt;
&lt;li&gt;the available navigation pathways between these screens&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The alternatives would have been to: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Look inside the collaborative design tool. However there was no representation of ALL the screens, but rather they were spread in multiple places, usually grouped by feature.&lt;/li&gt;
&lt;li&gt;Look inside the codebase, and follow the code. But this would be too tedious if you just want an overview of ALL the screens.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;This started as a side project that I played with in a few evenings, since I wasn't sure if the end result would look good, or if my colleagues would find it useful.&lt;/p&gt;

&lt;p&gt;The idea was simple: run a script that would generate a network graph made of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;nodes &lt;code&gt;[{ id, bundle }]&lt;/code&gt; - screens, grouped by their bundle&lt;/li&gt;
&lt;li&gt;edges &lt;code&gt;[{ from, to }]&lt;/code&gt; - directed arrows between the screens, indicating that the navigation between these 2 screens is possible.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These nodes and edges would be generated by looking through the codebase, with an algorithm described by the following pseudocode:&lt;/p&gt;

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

nodes = [];
edges = [];
bundles = findBundles(); // find all the src/screens/&amp;lt;bundle&amp;gt;
bundles.forEach(bundle =&amp;gt; {
  screens = findScreens(); // find all the src/screens/bundle/&amp;lt;screen&amp;gt;
  screens.forEach(screen =&amp;gt; {
    nodes.push({ id: screen, bundle  });
    paths = findDestinationPaths(); // regexp of PATH.[...] inside src/screens/bundle/screen
    paths.forEach(path =&amp;gt; {
      edges.push({ from: screen, to: mapPathToScreen(path) });
  });
});


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

&lt;/div&gt;

&lt;p&gt;This script will output 2 files: &lt;code&gt;nodes.js&lt;/code&gt; and &lt;code&gt;edges.js&lt;/code&gt;. These files were added to &lt;code&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Drawing the graph
&lt;/h2&gt;

&lt;p&gt;I used vis.js network library (&lt;a href="https://visjs.github.io/vis-network/" rel="noopener noreferrer"&gt;link&lt;/a&gt;) for drawing the network graph. &lt;/p&gt;

&lt;p&gt;This library comes with a few useful built-in features, out of which I used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;left-to-right hierarchical layout&lt;/li&gt;
&lt;li&gt;color grouping, based on the bundle&lt;/li&gt;
&lt;li&gt;physics engine, using repulsion solver&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;NOTE: I had to play around with some of the options, in order to find the ones that gave the best looking output.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Running the script
&lt;/h2&gt;

&lt;p&gt;I added a new script entry inside &lt;code&gt;package.json&lt;/code&gt;, that does:&lt;/p&gt;

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

"view-network": "node scripts/network/extract.js &amp;amp;&amp;amp; http-sever scripts/network/index.html


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

&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;index.html&lt;/code&gt; file will do a few things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;import the generated &lt;code&gt;nodes.js&lt;/code&gt; and &lt;code&gt;edges.js&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;import the drawing library&lt;/li&gt;
&lt;li&gt;draw the graph&lt;/li&gt;
&lt;li&gt;add extra UI features, such as a dropdown select menu, so that you can choose which bundles to view.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Result
&lt;/h2&gt;

&lt;p&gt;Here are 2 examples of graphs that can be generated:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;NOTE: I had to add some blur, so that I don't share confidential details.&lt;/em&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0u0pwgn5s84rnlj2jg6o.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%2Fuploads%2Farticles%2F0u0pwgn5s84rnlj2jg6o.png" alt="Example of network graph"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another example, using a different layout:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fg6sgq16z5ov5kgbgrdhe.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%2Fuploads%2Farticles%2Fg6sgq16z5ov5kgbgrdhe.png" alt="Another example of network graph"&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;Sometimes your side-projects can turn out to be useful for your company. &lt;/p&gt;

</description>
      <category>react</category>
      <category>network</category>
      <category>router</category>
      <category>graph</category>
    </item>
    <item>
      <title>The essence of The Pragmatic Programmer</title>
      <dc:creator>Manuel Micu</dc:creator>
      <pubDate>Sun, 15 Aug 2021 20:09:32 +0000</pubDate>
      <link>https://dev.to/manu4216/the-essence-of-the-pragmatic-programmer-5gle</link>
      <guid>https://dev.to/manu4216/the-essence-of-the-pragmatic-programmer-5gle</guid>
      <description>&lt;p&gt;I recently read the book &lt;a href="https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/"&gt;"The Pragmatic Programmer"&lt;/a&gt; and I'd like to share two lessons, which best capture the essence of the book.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Our job is to help people understand what [requirements] they want.
&lt;/h3&gt;

&lt;p&gt;Getting the requirements definition right is one of the most difficult part of the job.&lt;/p&gt;

&lt;p&gt;The initial requirements are just a suggestion, an invitation to explore all the options, and ask all the relevant questions that will help create refined requirements. &lt;/p&gt;

&lt;p&gt;Don't expect your product manager to give you the ready-to-code requirements. Do your job and help them understand what they want. &lt;/p&gt;

&lt;p&gt;Also don't get frustrated in the process. It is normal to require a few feedback loops.&lt;/p&gt;

&lt;p&gt;When you step-up and fulfill this part of the job, your company will value you more (and may give you a raise), and you will enjoy your work more.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Our job is not just "software developer". It's "problem solver".
&lt;/h3&gt;

&lt;p&gt;Writing code is a just one of the tools for solving a problem.&lt;/p&gt;

&lt;p&gt;Sometimes writing code may be the wrong solution, and would only create more problems. &lt;/p&gt;

&lt;p&gt;Other times, your code may just solve a symptom, but not the root cause of the problem.&lt;/p&gt;

&lt;p&gt;When you start seeing yourself as a problem solver, you start looking for solutions in all possible places. Not in the code that you usually write, but also in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a simple unix command (rather than your usual programming language)&lt;/li&gt;
&lt;li&gt;requirements that need to be further clarified,&lt;/li&gt;
&lt;li&gt;design that needs to be simplified,&lt;/li&gt;
&lt;li&gt;documentation that needs to be created.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You are not restricted to just writing code to address the problems that you are faced with.&lt;/p&gt;

&lt;p&gt;Once you realize this, and you &lt;strong&gt;take it upon yourself*&lt;/strong&gt; (defined as: &lt;em&gt;to accept responsibility for something without being asked to&lt;/em&gt;) to solve such problems, then you will be a step closer to become a &lt;em&gt;Pragmatic&lt;/em&gt; Programmer.&lt;/p&gt;

</description>
      <category>books</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to write clean functions</title>
      <dc:creator>Manuel Micu</dc:creator>
      <pubDate>Wed, 03 Jun 2020 19:10:34 +0000</pubDate>
      <link>https://dev.to/manu4216/how-to-write-clean-functions-bmh</link>
      <guid>https://dev.to/manu4216/how-to-write-clean-functions-bmh</guid>
      <description>&lt;p&gt;The following ideas are inspired by the book &lt;a href="https://www.amazon.com/Robert-Martin-Clean-Code-Collection-ebook/dp/B00666M59G"&gt;Clean Code&lt;/a&gt; by Robert C. Martin.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;This tutorial will demonstrate a set of basic principles that will help you write cleaner functions, that is, easy to read and easy to update.&lt;/p&gt;

&lt;p&gt;Most coding articles usually focus on the latest hot topics. There are not many articles about simple and sometimes undervalued ideas, like how to write clean code and clean functions.&lt;/p&gt;

&lt;p&gt;In this tutorial, you will practice writing clean functions, starting from an initial code sample, and improving it step by step using the following principles:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Small&lt;/li&gt;
&lt;li&gt;Do one thing&lt;/li&gt;
&lt;li&gt;One level of abstraction&lt;/li&gt;
&lt;li&gt;Less arguments the better&lt;/li&gt;
&lt;li&gt;No side effects&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These principles are relevant for any programming language, however the code samples will use JavaScript.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Basic knowledge of JavaScript.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 0 — Starting code
&lt;/h1&gt;

&lt;p&gt;You will start with the following code sample,  which does not satisfy any of the principles of clean functions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProductPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userCheckedPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;coupon&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unused&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*=&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 1 — Small
&lt;/h1&gt;

&lt;p&gt;Making an effort to keep your functions small, ideally between 1–5 lines, is the easiest way to make a function cleaner. Keeping this principle in mind will force you to reduce your function to its bare minimum.&lt;/p&gt;

&lt;p&gt;Go ahead, try to refactor this functions on your own first, then come back here and compare with the solution proposed bellow.&lt;/p&gt;

&lt;p&gt;We can make the main &lt;code&gt;getProductPrice&lt;/code&gt; function smaller by simply extracting some of its functionality into another &lt;code&gt;getPriceWithCouponOrSale&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getPriceWithCouponOrSale&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;coupon&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unused&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProductPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userCheckedPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getPriceWithCouponOrSale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;result&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 2 — Do one thing
&lt;/h1&gt;

&lt;p&gt;In the starting code sample, the function &lt;code&gt;getProductPrice&lt;/code&gt; does many things, all contained in the body of the function:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;it gets the original price&lt;/li&gt;
&lt;li&gt;it updates a product boolean&lt;/li&gt;
&lt;li&gt;it handles the error&lt;/li&gt;
&lt;li&gt;it applies a coupon or a sale&lt;/li&gt;
&lt;li&gt;it rounds the result&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In order to make a function do less things, you have 2 options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;move functionality one level down, by extracting a separate specialized function, like you did in step 1 with &lt;code&gt;getPriceWithCouponOrSale&lt;/code&gt; function.&lt;/li&gt;
&lt;li&gt;or move functionality one level up, at the caller level. By applying this approach, we could move the error handling out, and have a &lt;code&gt;getProductPrice&lt;/code&gt; function focused on one thing: getting the product price.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProductPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userCheckedPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getPriceWithCouponOrSale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalPrice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;round&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actualPrice&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For simplicity, the error handling on the caller level, is not reproduced.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3 — One level of abstraction
&lt;/h1&gt;

&lt;p&gt;This is something often overlooked, but it can make a major difference in achieving a clean, readable function. Mixing levels of abstraction inside a function is always confusing.&lt;/p&gt;

&lt;p&gt;For instance, in the starting code sample, besides the main level of abstraction (getting the final price), there is a mix of other levels of abstractions: error handling, details of price calculation, details of rounding up.&lt;/p&gt;

&lt;p&gt;The first 2 have already been removed in the previous steps. Go ahead and make the function cleaner by getting rid of the low level details of rounding up. The improved version will then look like so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProductPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userCheckedPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getPriceWithCouponOrSale&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;originalPrice&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;getRoundedValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actualPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This might not look like a big difference, but in reality, such things are like broken windows: once you have one in your code, new ones will add up.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 4 — Less arguments the better
&lt;/h1&gt;

&lt;p&gt;The ideal number of arguments is, in order: 0, 1, 2 arguments. Having more than 2 arguments becomes increasingly difficult to reason about, and it might be a sign that your function is doing too many things.&lt;/p&gt;

&lt;p&gt;In the previous step, &lt;code&gt;getProductPrice&lt;/code&gt; and &lt;code&gt;getPriceWithCouponOrSale&lt;/code&gt; use 3, and 4 arguments respectively. This is without doubt difficult to reason about. This can be simplified by simply extracting some of the arguments on top.&lt;/p&gt;

&lt;p&gt;Go ahead and try to find ways to pass less arguments to these functions.&lt;/p&gt;

&lt;p&gt;In the following proposed solution, this will be done by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;lifting &lt;code&gt;price&lt;/code&gt; argument on top of &lt;code&gt;getPriceWithCouponOrSale&lt;/code&gt; and make it return a fraction. This function will be renamed to &lt;code&gt;getReducedPriceFraction&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;lifting &lt;code&gt;isSaleActive&lt;/code&gt; and &lt;code&gt;coupon&lt;/code&gt; on top of &lt;code&gt;getProductPrice&lt;/code&gt;. They will be replaced with the new &lt;code&gt;reducedPriceFraction&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here is how the improved code will look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getReducedPriceFraction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;coupon&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unused&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reducedPriceFraction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getReducedPriceFraction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProductPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reducedPriceFraction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userCheckedPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalPrice&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;reducedPriceFraction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;getRoundedValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actualPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This approach can be taken further by repeating it one more time, which leads to the following code, in which &lt;code&gt;getReducedPriceFraction&lt;/code&gt; only uses 2 arguments, thus becoming much cleaner:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isCouponCompatible&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getReducedPriceFraction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isCouponValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isCouponValid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mf"&gt;0.8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isCouponValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;unused&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;isCouponCompatible&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;coupon&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reducedPriceFraction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;getReducedPriceFraction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isSaleActive&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isCouponValid&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProductPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reducedPriceFraction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userCheckedPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalPrice&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;reducedPriceFraction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;getRoundedValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actualPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Step 5 — No side effects
&lt;/h1&gt;

&lt;p&gt;Side effects make a function do unexpected things. Without having a closer look, you might have missed that &lt;code&gt;getProductPrice&lt;/code&gt; function also has a side effect: updating the &lt;code&gt;product&lt;/code&gt; object.&lt;/p&gt;

&lt;p&gt;This is dangerous because it can cause unexpected behaviours. For instance, in some other part of your code base, you might need to literally only get the product price, and introduce a bug because of this unexpected side effect.&lt;/p&gt;

&lt;p&gt;A clean function should do only one thing, without any hidden side effects. Such side effect should instead be done in plain sight, such as at the caller level, or in a separate function called &lt;code&gt;updateProduct&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In our previous code, you can remove the side effect and have it at the caller level (not reproduced). Once removed, you are left with a very clean function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getProductPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reducedPriceFraction&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;originalPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;getPrice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;product&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actualPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;originalPrice&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;reducedPriceFraction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;getRoundedValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;actualPrice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Congratulations! You succeeded in drastically improving the starting code sample by applying these 5 easy principles one by one.&lt;/p&gt;

&lt;p&gt;Hopefully this will help you identify opportunities to improve your own code base.&lt;/p&gt;

&lt;p&gt;Clean code and clean functions are a joy to read and work on. Spread that joy by writing clean functions!&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>functional</category>
    </item>
  </channel>
</rss>
