<?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: Nik Poltoratsky</title>
    <description>The latest articles on DEV Community by Nik Poltoratsky (@nikpoltoratsky).</description>
    <link>https://dev.to/nikpoltoratsky</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%2F192669%2Fd0a94367-7ec4-462b-9947-6f6d3b2eea0f.jpg</url>
      <title>DEV Community: Nik Poltoratsky</title>
      <link>https://dev.to/nikpoltoratsky</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nikpoltoratsky"/>
    <language>en</language>
    <item>
      <title>How to Create an Admin Panel for Your PostgreSQL Database on Railway Cloud</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Tue, 12 Mar 2024 13:27:27 +0000</pubDate>
      <link>https://dev.to/nikpoltoratsky/how-to-create-an-admin-panel-for-your-postgresql-database-on-railway-cloud-1gib</link>
      <guid>https://dev.to/nikpoltoratsky/how-to-create-an-admin-panel-for-your-postgresql-database-on-railway-cloud-1gib</guid>
      <description>&lt;p&gt;Creating an effective admin panel for your PostgreSQL database hosted on Railway Cloud can significantly streamline the management of your database records. This guide will walk you through the steps to build a fully functional admin panel using &lt;a href="https://uibakery.io/" rel="noopener noreferrer"&gt;UI Bakery&lt;/a&gt;, a visual application builder. This panel will allow you to view, edit, add, and delete records, as well as filter data for easier access.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgeetjx4uspizo96g4vub.gif" 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%2Fgeetjx4uspizo96g4vub.gif" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you prefer video content, here’s my video explaining how to make an admin panel for the railway-hosted PostgreSQL.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/NzEoPTpmUM8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 1: Connect Your Database to &lt;a href="https://uibakery.io/" rel="noopener noreferrer"&gt;UI Bakery&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Navigate to Data Sources in &lt;a href="https://uibakery.io/" rel="noopener noreferrer"&gt;UI Bakery&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1t295yzxr9w0gkf71qk5.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%2F1t295yzxr9w0gkf71qk5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Start by going to the data sources section within UI Bakery.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect to PostgreSQL
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fklihxopqrz98ngbslrj5.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%2Fklihxopqrz98ngbslrj5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on the "connect" button and select PostgreSQL from the list of options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8fe8zjbddk0n6a3tavx4.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%2F8fe8zjbddk0n6a3tavx4.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter Database Credentials: Input the required credentials for your database. You can find these details in your Railway dashboard under your database's "variables" section. The necessary credentials include the database host, password, port, and user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Connect Data Source
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fleszrgd0e0w2fyhzazgw.gif" 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%2Fleszrgd0e0w2fyhzazgw.gif" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After filling in the credentials, click the "connect data source" button. Once connected, you should be able to see your database's table structure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2: Create a New Application
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flhv3yk02reeane2cbppb.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%2Flhv3yk02reeane2cbppb.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From your workspace in UI Bakery, create a new application. For this example, we'll name it "Clients Admin".&lt;/p&gt;

&lt;p&gt;Create the First Action: This action will load data from your database table. Execute this action to ensure it works correctly and that the data preview is loaded.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkwro9iojd2noxoai9b6x.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%2Fkwro9iojd2noxoai9b6x.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First of all, press "Create action"&lt;/li&gt;
&lt;li&gt;Then choose the "Clients" data source you've added in the previous step&lt;/li&gt;
&lt;li&gt;In &lt;strong&gt;operation&lt;/strong&gt; select &lt;strong&gt;Load Table&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Finally, choose the &lt;strong&gt;Clients&lt;/strong&gt; table to load&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Execute the action to make sure everything is connected and works properly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzlsku53gcnaaa39l9u2h.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%2Fzlsku53gcnaaa39l9u2h.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3: Display Data
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Configure a Data Table
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0363z54ens29mohkdmr5.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%2F0363z54ens29mohkdmr5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Add a table on the screen to display the loaded data. Adjust the size, remove any unnecessary columns for clarity, and customize the display of certain data in &lt;strong&gt;columns&lt;/strong&gt; settings.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 4: Enable and Configure CRUD Operations
&lt;/h2&gt;

&lt;p&gt;First of all, scroll to the &lt;strong&gt;actions&lt;/strong&gt; section of the table configuration and enable &lt;strong&gt;add&lt;/strong&gt;, &lt;strong&gt;edit&lt;/strong&gt;, and &lt;strong&gt;delete&lt;/strong&gt; buttons.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feipfb8jeodma9w8xsz35.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%2Feipfb8jeodma9w8xsz35.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then scroll down to the &lt;strong&gt;triggers&lt;/strong&gt; section and create new actions for &lt;strong&gt;On Create&lt;/strong&gt;, &lt;strong&gt;On Edit&lt;/strong&gt;, and &lt;strong&gt;On Delete&lt;/strong&gt; triggers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7ngu5wqaonb52k7xmwgk.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%2F7ngu5wqaonb52k7xmwgk.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Editing Records
&lt;/h3&gt;

&lt;p&gt;In newly created &lt;strong&gt;onEdit&lt;/strong&gt; action choose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type&lt;/strong&gt; - &lt;strong&gt;Clients&lt;/strong&gt; data source&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operation&lt;/strong&gt; - Update Row&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Table&lt;/strong&gt; - &lt;strong&gt;Clients&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then in &lt;strong&gt;Configure filter to update record(s)&lt;/strong&gt; section define which records have to be updated - add an &lt;strong&gt;id&lt;/strong&gt; filter that &lt;strong&gt;equals&lt;/strong&gt; to the &lt;code&gt;{{ui.clientsTable.editedRow.data.id}}&lt;/code&gt; - edited row id.&lt;/p&gt;

&lt;p&gt;Toggle &lt;strong&gt;JS&lt;/strong&gt; mode in &lt;strong&gt;Configure record fields to update&lt;/strong&gt; section and pass &lt;code&gt;{{ui.clientsTable.editedRow.data}}&lt;/code&gt; inside - updated record from the table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdfi0x7eq26gobttmxt78.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%2Fdfi0x7eq26gobttmxt78.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After editing, execute the load action again to refresh the data displayed on your panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdmigwk3r8e40afhkefam.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%2Fdmigwk3r8e40afhkefam.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Adding New Records
&lt;/h3&gt;

&lt;p&gt;In newly created &lt;strong&gt;onCreate&lt;/strong&gt; action choose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type&lt;/strong&gt; - &lt;strong&gt;Clients&lt;/strong&gt; data source&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operation&lt;/strong&gt; - Create Row&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Table&lt;/strong&gt; - &lt;strong&gt;Clients&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then in &lt;strong&gt;Configure new record fields&lt;/strong&gt; section add &lt;code&gt;{{ui.clientsTable.newRow.data}}&lt;/code&gt; - a new object submitted from the table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2mqx4cgv6kc4yurgv8w3.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%2F2mqx4cgv6kc4yurgv8w3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After submitting a new row, execute the load action again to refresh the data displayed on your panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3cabe1xwft98ugy75m9y.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%2F3cabe1xwft98ugy75m9y.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Deleting Records
&lt;/h3&gt;

&lt;p&gt;In &lt;strong&gt;onDelete&lt;/strong&gt; action choose:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Type&lt;/strong&gt; - &lt;strong&gt;Clients&lt;/strong&gt; data source&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Operation&lt;/strong&gt; - Delete Row&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Table&lt;/strong&gt; - &lt;strong&gt;Clients&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In &lt;strong&gt;Configure filter to delete record(s)&lt;/strong&gt; section define which records have to be updated - add an &lt;strong&gt;id&lt;/strong&gt; filter that &lt;strong&gt;equals&lt;/strong&gt; to the &lt;code&gt;{{ui.clientsTable.deletedRow.data.id}}&lt;/code&gt; - deleted row id.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcy5zjfzhq07b13qv6he.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%2Fjcy5zjfzhq07b13qv6he.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After deleting a row, execute the load action again to refresh the data displayed on your panel.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2rivohi1zpwgmrr091x9.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%2F2rivohi1zpwgmrr091x9.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 5: Implement Filtering
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Add a Filter Input
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0sgb1c0yt2fwb1em7oat.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%2F0sgb1c0yt2fwb1em7oat.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Place an input field (e.g., findByName) in your admin panel's header for filtering capabilities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configure Filtering
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxbl9zxij0upcszkdoqna.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%2Fxbl9zxij0upcszkdoqna.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Link the input field to the load action with &lt;strong&gt;onChange&lt;/strong&gt; trigger, adjusting the action to include filters based on the input value (e.g., records where the name matches the input value).&lt;/p&gt;

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

&lt;p&gt;By following these steps, you have created a comprehensive admin panel for managing your PostgreSQL database on Railway Cloud with UI Bakery. This panel not only streamlines the process of viewing and manipulating database records but also enhances the efficiency of database management through filtering and CRUD operations. Join UI Bakery to further expedite your application development journey.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>lowcode</category>
      <category>railway</category>
      <category>postgres</category>
    </item>
    <item>
      <title>How to create Supabase admin dashboard?</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Tue, 13 Feb 2024 14:36:07 +0000</pubDate>
      <link>https://dev.to/nikpoltoratsky/how-to-create-supabase-admin-dashboard-4glj</link>
      <guid>https://dev.to/nikpoltoratsky/how-to-create-supabase-admin-dashboard-4glj</guid>
      <description>&lt;p&gt;In this article, the database meets ui!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3h4u3c6i0om0w589dnqz.gif" 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%2F3h4u3c6i0om0w589dnqz.gif" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will find how to build an Admin Dashboard on top of Supabase using &lt;a href="https://uibakery.io/" rel="noopener noreferrer"&gt;UI Bakery&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Connect Supabase to UI Bakery&lt;/li&gt;
&lt;li&gt;View Supabase data&lt;/li&gt;
&lt;li&gt;Add form to edit records&lt;/li&gt;
&lt;li&gt;Publish an app to make it available for your users&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://supabase.com/" rel="noopener noreferrer"&gt;Supabase&lt;/a&gt; is an open-source Firebase alternative. It’s built on top of PostgreSQL and stuffed with many features such as database, auth, storage, REST, and GraphQL APIs. Everything is backed in a modern intuitive no-code UI. All that makes it a good choice for your database while &lt;a href="https://uibakery.io/" rel="noopener noreferrer"&gt;UI Bakery&lt;/a&gt; will focus on the UI.&lt;/p&gt;

&lt;p&gt;In this tutorial, I’ll show you how to create an admin panel for your supabase database using &lt;a href="https://uibakery.io/" rel="noopener noreferrer"&gt;UI Bakery&lt;/a&gt;. Here is what we’ll build - an admin panel that can view data from the database and provides a user-friendly interface for records editing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.ibb.co%2FgtBQrdL%2F1-what-we-ll-build.gif" 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%2Fi.ibb.co%2FgtBQrdL%2F1-what-we-ll-build.gif"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;If you prefer video content, here’s my video explaining how to make a supabase admin.&lt;/p&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/ul45AXxEZb8"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;h2&gt;
  
  
  Connect supabase to UI Bakery
&lt;/h2&gt;

&lt;p&gt;First things first, let’s connect the supabase db to UI Bakery.&lt;/p&gt;

&lt;p&gt;Open your supabase project, go to the “Project Settings” → “Database”. Here in the “Connection parameters” section, you’ll find the database credentials required for connection:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2hjoh0ihfj50x6dflzos.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%2F2hjoh0ihfj50x6dflzos.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, in your &lt;a href="https://uibakery.io/" rel="noopener noreferrer"&gt;UI Bakery&lt;/a&gt; workspace, go to “Data Sources” → “Connect”. In the connection form, fill in the credentials copied from the “Connection parameters” section of the database settings.&lt;/p&gt;

&lt;p&gt;Press “Connect Datasource” and supabase integration is done. Now we can build an actual application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fut9x48goyht6efzjhcaq.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%2Fut9x48goyht6efzjhcaq.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  View supabase data
&lt;/h2&gt;

&lt;p&gt;In the UI Bakery workspace, click “Create app” → “Create new app”, fill in the application name, and click “Create app”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F91w09q9it92q0a91zg4p.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%2F91w09q9it92q0a91zg4p.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you’re in an application builder. Here you can see 3 major panels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Left - components list, here you will find components to add to the screen.&lt;/li&gt;
&lt;li&gt;Right - Selected component configuration where you change component properties.&lt;/li&gt;
&lt;li&gt;Bottom - actions panel - all the application logic lives here.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's focus on data first - create a new action that will load data from the connected supabase db. In the &lt;strong&gt;actions panel&lt;/strong&gt; click “Create action”, choose your supabase database connected before, then “Load table” and finally choose a table to load. When configuration is done click “Execute action” to preview the data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhw3gwhnqbw5o8spk0s8q.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%2Fhw3gwhnqbw5o8spk0s8q.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When data is loaded in UI Bakery we can start building UI. First of all, let's add a table to view records. Find the Table in the components panel, then drag-drop it on the working area.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F64rapvcqhy06fjovqpqc.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%2F64rapvcqhy06fjovqpqc.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using the component settings panel configure what columns are displayed and change the title of the table:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffr7eq03ygujrrcwfcz9t.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%2Ffr7eq03ygujrrcwfcz9t.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this stage, you have an application that loads data from the supabase database and displays it inside a good-looking table. Now it’s time to focus on records editing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Add form to edit records
&lt;/h2&gt;

&lt;p&gt;Drag’n’drop a &lt;strong&gt;form&lt;/strong&gt; component from the &lt;strong&gt;components&lt;/strong&gt; panel to the working area to the right of the table. When a component is in its place we have to configure it to display data from the &lt;strong&gt;selected row&lt;/strong&gt; of the table.&lt;br&gt;
Locate the &lt;strong&gt;Data&lt;/strong&gt; field in the “Component settings” sidebar and reference the table’s selected row data using variable syntax - &lt;code&gt;{{ui.clientsTable.selectedRow.data}}&lt;/code&gt;. Curly braces allow using variables in components settings fields. &lt;strong&gt;&lt;code&gt;{{ui&lt;/code&gt;&lt;/strong&gt; - means we’re referencing UI component from the workspace. &lt;strong&gt;&lt;code&gt;{{ui.clientsTable&lt;/code&gt;&lt;/strong&gt; - means we’re referencing a component called “clientsTable”, and &lt;strong&gt;&lt;code&gt;{{ui.clientsTable.selectedRow.data}}&lt;/code&gt;&lt;/strong&gt; means to get the data from the selected row of our table.&lt;/p&gt;

&lt;p&gt;When the &lt;strong&gt;Data&lt;/strong&gt; field is set, hit the “Regenerate structure” button and the form will apply the referenced table structure to itself so you don’t have to configure the form structure. It will just be the same as in your table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fyd0o6jm600p0486qs6gc.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%2Fyd0o6jm600p0486qs6gc.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To make this form update records in the database you have to scroll the “component settings” panel to the bottom and find the “Triggers” section. There hit “Add trigger”, select “On Submit” to trigger the action when the form is submitted, and click “Create action” to add a new action assigned to the “On Submit” trigger.&lt;/p&gt;

&lt;p&gt;At the “Actions” panel a new empty action appears. In the opened popup select your supabase database we connected before → “update Row” → supabase table to update.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj97nlvdzubrlgclbfch3.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%2Fj97nlvdzubrlgclbfch3.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After that, we should configure an update behavior. In “Configure filter to update record(s)” type &lt;em&gt;&lt;code&gt;{{ui.clientForm.value.id}}&lt;/code&gt; -&lt;/em&gt; reference an &lt;strong&gt;ID&lt;/strong&gt; of the record in the form.&lt;/p&gt;

&lt;p&gt;Then, to the right of the “Configure record fields to update” field, click on the “JS” button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjcz65jf8ad6e0gnr5iut.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%2Fjcz65jf8ad6e0gnr5iut.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will turn the form into a code field, so we can just reference the whole form value using variable syntax &lt;code&gt;{{ui.clientForm.value}}&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fknyjn1ygv5g9c374s7br.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%2Fknyjn1ygv5g9c374s7br.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So this action does the following - it will find all the records with IDs equal to the entity ID and update all the fields changed in the form.&lt;/p&gt;

&lt;p&gt;The last step we have to perform here is to reload data in the table.&lt;/p&gt;

&lt;p&gt;Create a new action step below the “update” step, choose “Execute action” and in the “Action to execute” field choose the “loadClients” action. This configuration will trigger the “loadClients” action right after the database record is updated. So we’ll always have fresh data in the table.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe2wtnvg4thnw1zbupspu.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%2Fe2wtnvg4thnw1zbupspu.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Publish an app to make it available for your users
&lt;/h2&gt;

&lt;p&gt;Finally, to make an application available for your users you have to publish it. Click the “Release” button at the top right corner and hit “Publish release”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frkf5c9x4iw9677orazof.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%2Frkf5c9x4iw9677orazof.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now your supabase application is up and running! The only thing left to do is invite your users.&lt;br&gt;
In the workspace, click on your email → “Users &amp;amp; Permissions”. There you’ll be able to invite your teammates to collaborate in your app.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjbrkjxstak6689y5do8a.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%2Fjbrkjxstak6689y5do8a.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now you have a neat-looking supabase admin panel where you can view and edit your data.&lt;/p&gt;

&lt;p&gt;Using UI Bakery builder you can add other features to your app, protect them using roles and permissions, adapt an app for mobile devices, customize the look and feel of your application using a theme editor, and many many more.&lt;/p&gt;

&lt;p&gt;All of that in a fraction of a minute.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3lrvj3s1f6qdiq5zyyd1.gif" 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%2F3lrvj3s1f6qdiq5zyyd1.gif" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cloud.uibakery.io/auth/register" rel="noopener noreferrer"&gt;Join UI Bakery community&lt;/a&gt; and build applications in minutes - not months!&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>supabase</category>
      <category>lowcode</category>
    </item>
    <item>
      <title>Open-Source Headless CMS in 2024</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Tue, 30 Jan 2024 13:08:38 +0000</pubDate>
      <link>https://dev.to/nikpoltoratsky/open-source-headless-cms-in-2024-57ko</link>
      <guid>https://dev.to/nikpoltoratsky/open-source-headless-cms-in-2024-57ko</guid>
      <description>&lt;p&gt;In the roaring digital arena of 2024, the open-source headless CMS scene isn't just evolving; it's detonating with revolutionary fervor. These platforms aren't merely tools; they're the maverick spirits driving a relentless push against the digital status quo. Let’s dive headfirst into the anarchic world of the top 8 headless CMS platforms that are rewriting the code of digital rebellion.&lt;/p&gt;

&lt;h2&gt;
  
  
  You know what would be awesome?
&lt;/h2&gt;

&lt;p&gt;If you check before we begin - low code builder with superpowers for dashboards and internal apps&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6suffxocpasu0edt7lz.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj6suffxocpasu0edt7lz.gif" alt="Image description" width="480" height="260"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://uibakery.io"&gt;https://uibakery.io&lt;/a&gt;&lt;br&gt;
I am a software developer in a bootstrapped company UI BAKERY, which is an alternative to Retool.&lt;br&gt;
Check UI BAKERY&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;a href="https://strapi.io/"&gt;Strapi: The Code Anarchist&lt;/a&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;⭐️ 58,615&lt;br&gt;
&lt;a href="https://github.com/strapi"&gt;https://github.com/strapi&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1j2w8v0acih7gg8c8hce.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1j2w8v0acih7gg8c8hce.png" alt="Image description" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
Strapi isn't just coding outside the lines – it's tearing them up. This Node.js rebel yells defiance with its RESTful and GraphQL APIs, empowering developers to not just build but to conquer. It's a declaration of independence in the CMS world, a flag planted firmly in the territory of innovation and unrestricted creativity.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;a href="https://keystonejs.com/"&gt;Keystone 6: The GraphQL Behemoth&lt;/a&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;⭐️ 8,700&lt;br&gt;
&lt;a href="https://github.com/keystonejs"&gt;https://github.com/keystonejs&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fplphwg00wcdreogfazht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fplphwg00wcdreogfazht.png" alt="Keystone 6" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
Keystone 6 isn’t just stepping up the game; it’s smashing it with a sledgehammer. This GraphQL behemoth, with its Node.js roots, is tearing down walls and building empires of content that defy convention and embrace the extraordinary.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;a href="https://ghost.org/"&gt;Ghost: The Underground Storyteller&lt;/a&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;⭐️ 45,000&lt;br&gt;
&lt;a href="https://github.com/tryghost/ghost/stargazers"&gt;https://github.com/tryghost/ghost/stargazers&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F012395s93ox1tl5ubgg4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F012395s93ox1tl5ubgg4.png" alt="Ghost" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
Ghost is more than a CMS; it's a whisper in the digital night, a storyteller weaving narratives in the underground. For the bloggers and content punks, Ghost brings Markdown, mobile optimization, and a slick, streamlined approach to shaking up the content cosmos.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;a href="https://directus.io/"&gt;Directus: The Shape-Shifting Maverick&lt;/a&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;⭐️ 24,540&lt;br&gt;
&lt;a href="https://github.com/directus"&gt;https://github.com/directus&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqabki4n91toraw945jil.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqabki4n91toraw945jil.png" alt="Directus" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
Directus doesn't just adapt; it transforms. This platform is a shape-shifting maverick, constantly evolving and redefining what it means to manage content. Armed with GraphQL and REST APIs, it’s a chameleon in a world of monochrome CMSs.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;a href="https://www.decapcms.com/"&gt;Decap CMS: The Static Site Outlaw&lt;/a&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;⭐️ 17,300&lt;br&gt;
&lt;a href="https://github.com/decaporg"&gt;https://github.com/decaporg&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4hlim4larjy10io1w1j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fn4hlim4larjy10io1w1j.png" alt="Decap CMS" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
Decap CMS rides in like an outlaw in the static website world. It’s not just a tool; it's a revolution, bringing a Git-based system and intuitive editor to the static site landscape, leaving a trail of transformed, high-octane websites in its wake.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;a href="https://payloadcms.com/"&gt;Payload CMS: The Customization Insurgent&lt;/a&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;⭐️ 17,084&lt;br&gt;
&lt;a href="https://github.com/payloadcms/payload"&gt;https://github.com/payloadcms/payload&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzm89e6m9uwas08iuqr8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzm89e6m9uwas08iuqr8g.png" alt="Payload CMS" width="800" height="500"&gt;&lt;/a&gt;&lt;br&gt;
Payload CMS is where rebellion meets customization. This Node.js, Express, and MongoDB titan is smashing through the barriers of conventional CMSs, offering a realm where customization isn’t just a feature; it's a battle cry for unshackled creative freedom.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;&lt;a href="https://tina.io/"&gt;Tina CMS: The Editing Renegade of React&lt;/a&gt;&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;⭐️ 10,704&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/tinacms/tinacms"&gt;https://github.com/tinacms/tinacms&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy430av08bbvleefnjk2b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy430av08bbvleefnjk2b.png" alt="Tina CMS" width="800" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Tina CMS isn’t just playing with React; it’s setting it on fire. It's an editing renegade, transforming the React scene with inline editing capabilities that turn every keystroke into a radical act of digital defiance.&lt;/p&gt;




&lt;p&gt;In 2024, these open-source headless CMS platforms aren't just part of the digital revolution; they're leading it. With each line of code, they challenge the norms, push the boundaries, and empower the rebels and dreamers. They aren't just building websites; they're crafting digital revolutions. Dive into these platforms, and join the headless CMS rebellion, where every click is a call to digital arms!&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>webdev</category>
      <category>cms</category>
      <category>javascript</category>
    </item>
    <item>
      <title>10 Web Dev Tips to Stay on the Wave in 2024</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Tue, 23 Jan 2024 09:34:28 +0000</pubDate>
      <link>https://dev.to/nikpoltoratsky/10-web-dev-tips-to-stay-on-the-wave-in-2024-45la</link>
      <guid>https://dev.to/nikpoltoratsky/10-web-dev-tips-to-stay-on-the-wave-in-2024-45la</guid>
      <description>&lt;p&gt;Welcome to 2024's dynamic web development scene, where innovation is essential. This landscape is defined by rapidly evolving technologies and user needs, posing exciting challenges for developers.&lt;br&gt;
In this exploration of the top 10 web development trends, I will uncover how each trend, from Progressive Web Apps to AI integration, is transforming digital creation and interaction. These trends aren't just about technology; they're shaping our digital future.&lt;br&gt;
Before we begin:&lt;/p&gt;

&lt;h2&gt;
  
  
  Check UI BAKERY
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgkcwy1opv0wxomh83r0.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbgkcwy1opv0wxomh83r0.gif" alt="Image description" width="480" height="270"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://uibakery.io"&gt;https://uibakery.io&lt;/a&gt;&lt;br&gt;
I am a software developer in a bootstrapped company UI BAKERY, which is an alternative to Retool.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;strong&gt;Progressive Web Apps (PWAs)&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;PWAs are not just a trend; they're a paradigm shift. Imagine applications that load like regular web pages but offer functionalities like working offline, receiving push notifications, and having a presence on the home screen. The trick is in mastering service workers for offline capabilities and utilizing caches for speed. The challenge lies in designing for various form factors while keeping the app-like feel. PWAs are especially crucial for reaching users in regions with limited internet connectivity or on lower-end devices.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;strong&gt;API-First Design&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Gone are the days when APIs were an afterthought. In 2024, the API-first design is central to web development. This approach starts with a clear contract for the API, focusing on the endpoints, resources, and data formats before writing any code. The goal is to create APIs that are robust enough to serve as the backbone of both the front-end and back-end systems. This trend is driven by the rise of microservices and the need for better integration capabilities in an increasingly interconnected digital ecosystem.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;strong&gt;Blockchain-Based Applications&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnyu9o30gpbmd9htbiach.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnyu9o30gpbmd9htbiach.png" alt="Blockchain-Based Applications" width="800" height="369"&gt;&lt;/a&gt;&lt;br&gt;
Blockchain in web development extends beyond cryptocurrencies. It’s about creating a layer of trust and security in web interactions. Blockchain can be used for secure transactions, verifying identities, and ensuring data integrity. The decentralized nature of blockchain opens up possibilities for developing applications where data security and integrity are paramount. As a developer, understanding blockchain's implications on web architecture, data storage, and user authentication will be crucial.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;strong&gt;Machine Learning in the Browser&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Bringing machine learning to the client side with libraries like TensorFlow.js isn't just about personalization; it's about unlocking a new level of user interaction. This involves training models in the browser, which requires understanding both the technical aspects of machine learning and the ethical considerations of user data. The challenge here is to use these capabilities responsibly and create experiences that are both intelligent and respectful of privacy.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;strong&gt;Motion UI&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4gdyht3vesqjm9ogu49v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4gdyht3vesqjm9ogu49v.png" alt="Motion UI" width="800" height="279"&gt;&lt;/a&gt;&lt;br&gt;
In an era where user attention is at a premium, Motion UI can be the difference between a good and great user experience. It's more than just aesthetics; it's about using animation strategically to guide user actions, provide feedback, and make web applications feel more intuitive. The challenge is to integrate Motion UI in a way that enhances usability without compromising performance. This requires a deep understanding of CSS, JavaScript, and the principles of animation.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. &lt;strong&gt;Low-Code and No-Code Development&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdb99c7uwrg9wwp0yygdj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdb99c7uwrg9wwp0yygdj.png" alt="Low-Code" width="800" height="455"&gt;&lt;/a&gt;&lt;br&gt;
The rise of low-code and no-code platforms is democratizing web development, but it also raises the bar for professional developers. These platforms can accelerate development, enable rapid prototyping, and free up developers to focus on more complex aspects of web applications. Understanding how to leverage these platforms, integrate them into your workflows, and customize their offerings can give you a significant edge in the market.&lt;br&gt;
&lt;a href="https://uibakery.io"&gt;UI Bakery is an example of low-code&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. &lt;strong&gt;Cybersecurity by Design&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpy0gvqw1fq3od4gtcbth.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpy0gvqw1fq3od4gtcbth.png" alt="Cybersecurity by Design" width="800" height="399"&gt;&lt;/a&gt;&lt;br&gt;
With the increasing frequency and sophistication of cyber attacks, a proactive approach to security is a must. This involves incorporating security practices throughout the development process - from initial design through development, testing, and deployment. It's about understanding the latest security threats, staying updated with security best practices, and developing a security-centric mindset.&lt;/p&gt;

&lt;h3&gt;
  
  
  8. &lt;strong&gt;Artificial Intelligence Integration&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8v9b410cc66unthxtgnu.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8v9b410cc66unthxtgnu.gif" alt="Image description" width="360" height="203"&gt;&lt;/a&gt;&lt;br&gt;
AI's role in web development is expanding rapidly. From enhancing user experience through chatbots and personalized content to automating backend processes, AI is becoming a staple in the web developer's toolkit. The challenge lies in understanding AI algorithms, managing data ethically, and integrating AI smoothly into web applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  9. &lt;strong&gt;Extended Reality (XR) Experiences&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch57wwsudr12f1ewdrq0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fch57wwsudr12f1ewdrq0.png" alt="Extended Reality " width="800" height="369"&gt;&lt;/a&gt;&lt;br&gt;
XR is pushing the boundaries of web experiences. This involves integrating AR and VR elements into web applications, creating immersive and interactive experiences that go beyond the screen. This trend is not just about the &lt;strong&gt;wow factor&lt;/strong&gt;; it's about exploring new ways to engage users, provide valuable experiences, and leverage the capabilities of modern browsers and hardware.&lt;/p&gt;

&lt;h3&gt;
  
  
  10. &lt;strong&gt;Voice Search Optimization&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;With voice assistants becoming increasingly common, optimizing for voice search is more important than ever. This is not just about keywords; it's about understanding natural language processing, structuring content for conversational queries, and ensuring that your web applications are accessible via voice commands. The challenge is to create content that is easily discoverable and navigable through voice, while also providing a rich user experience.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;I hope you enjoyed the trends. Which trends did I miss?&lt;br&gt;
&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4ub344bvorutpw03iqe.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp4ub344bvorutpw03iqe.gif" alt="Image description" width="400" height="226"&gt;&lt;/a&gt;&lt;br&gt;
Thanks from me and &lt;a href="https://uibakery.io"&gt;UI Bakery&lt;/a&gt; team ✨&lt;br&gt;
These trends represent a mix of new technologies, evolving best practices, and shifts in user expectations. As developers, staying informed and adaptable is key to not just riding the wave, but shaping it.&lt;br&gt;
Embracing these trends will not only keep your skills relevant but also enable you to innovate and lead in creating more effective, engaging, and secure web solutions. In the rapidly evolving world of web development, your ability to integrate these cutting-edge trends can set you apart and position you at the forefront of the digital future.&lt;br&gt;
Remember, each trend offers a unique opportunity to expand your toolkit and perspective. So, keep learning, experimenting, and pushing the boundaries to create web experiences that aren't just functional, but truly remarkable. 🚀🌐&lt;/p&gt;

</description>
      <category>lowcode</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
    <item>
      <title>7 Programming Riddles That Even Elite Coders Can't Solve</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Mon, 20 Nov 2023 15:06:38 +0000</pubDate>
      <link>https://dev.to/uibakery/7-programming-riddles-that-even-elite-coders-cant-solve-m45</link>
      <guid>https://dev.to/uibakery/7-programming-riddles-that-even-elite-coders-cant-solve-m45</guid>
      <description>&lt;p&gt;In 1996 Phil Karlton said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are only two hard things in Computer Science: cache invalidation and naming things.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This quote evolved in &lt;a href="https://martinfowler.com/bliki/TwoHardThings.html"&gt;different ways&lt;/a&gt; and my favorite one is:&lt;/p&gt;

&lt;p&gt;&lt;iframe class="tweet-embed" id="tweet-506010907021828096-473" src="https://platform.twitter.com/embed/Tweet.html?id=506010907021828096"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-506010907021828096-473');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=506010907021828096&amp;amp;theme=dark"
  }



 &lt;/p&gt;

&lt;p&gt;I’m not as experienced as the guys above however I have my personal list of annoying programming issues I’m facing frequently. This is this list - a collection of the complex topics in programming that have no solution yet backed by my stories (sure, original problems are included, looks like they’re eternal):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Cache invalidation&lt;/li&gt;
&lt;li&gt;Scrolling&lt;/li&gt;
&lt;li&gt;When to upgrade?&lt;/li&gt;
&lt;li&gt;Naming things&lt;/li&gt;
&lt;li&gt;N+1&lt;/li&gt;
&lt;li&gt;Dates&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;
  
  
  Cache invalidation
&lt;/h2&gt;

&lt;p&gt;In a nutshell, cache invalidation is a tough challenge. It’s been one of the most stubborn problems in programming for decades, and we're still hunting for the one solution to rule them all. Whenever this problem shows up, it eats away at our valuable time.&lt;/p&gt;

&lt;p&gt;From my own programming journey, I've found that the major headache of cache invalidation isn't about deciding when it's time to invalidate the cache, balancing performance, and data accuracy. No, the real problem is &lt;em&gt;Understanding that the problem comes from the cache.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The sequence usually unfolds like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The support team flags a concern - the customer changes things, and the system says it's okay, but the old information stays there.&lt;/li&gt;
&lt;li&gt;You try to replicate it on your local machine or the dev or staging server – everything's flawless there.&lt;/li&gt;
&lt;li&gt;Sure, you're diving in to understand more about the situation, asking questions such as:

&lt;ul&gt;
&lt;li&gt;Did the update really go through?&lt;/li&gt;
&lt;li&gt;Is there a bug causing the system to claim success prematurely?&lt;/li&gt;
&lt;li&gt;If the update was implemented, was the data refreshed properly?&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;After a long and thorough check, you find that everything seems fine, but frustratingly, the problem doesn't happen very often.&lt;/li&gt;
&lt;li&gt;Later, after spending many hours trying to fix the issue, you discover a hidden &lt;em&gt;if/else&lt;/em&gt; statement that was added by someone who left the company two years ago.&lt;/li&gt;
&lt;li&gt;Stop. Pause. Think. F*ck it. Suddenly, you realize it’s a unique caching setup for a specific situation that you wouldn't expect unless you knew about it beforehand. But really, how could you have guessed?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's just one-half of the problem. What if the caching system lurks outside your code? My favorite troublemaker here is Hibernate. For those familiar with Hibernate, you know exactly what I'm talking about. For those who aren't, let's just say you're in for a big surprise.&lt;/p&gt;

&lt;p&gt;Even after looking through lots of articles and videos, every few months, I encounter errors because of Hibernate. When it comes to caching, Hibernate can be a ruthless monster, ready to consume your peace of mind unless you handle it with extreme caution.&lt;/p&gt;


&lt;h2&gt;
  
  
  Scrolling
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fempbp38f5v7eh6mg26in.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fempbp38f5v7eh6mg26in.png" alt="elder scrolls" width="472" height="338"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I have experience in both frontend and backend development, but with my roots in frontend, I've developed a firsthand understanding of the fascinating world of scrolls. Trust me, it's more twisted than one might expect.&lt;/p&gt;

&lt;p&gt;Primarily, customization! These subtle elements in your browser are unique across different platforms - be it Mac, Linux, or Windows, and not to mention browsers such as Chrome, Safari, or Firefox. Even though their look differs everywhere, they resist you when you try to customize their look uniformly across platforms, which frustrates our design team.&lt;/p&gt;

&lt;p&gt;The story takes another twist when we bring in our love for MacBooks and our preference for hiding scrolls in our browsers. Unintentionally, we blind ourselves to blatant scrolling issues that go off to see the world in production. Surprise, surprise, scrolls pop up in the most unexpected places!&lt;/p&gt;

&lt;p&gt;To tackle this, we created a dedicated channel to post about any scrolling anomalies we come across:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Femgjhb39g0yrhcgr551y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Femgjhb39g0yrhcgr551y.png" alt="default scroll in heading" width="520" height="278"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmov701qf21biw38nji4t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmov701qf21biw38nji4t.png" alt="default scroll in json editor" width="475" height="480"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7fpmt05onkxb75zy5mc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy7fpmt05onkxb75zy5mc.png" alt="default scroll in actions" width="800" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Meanwhile, our design ideal remains the humble "Small Neat Scroll”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx444f6t7ab9vizcvmw7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqx444f6t7ab9vizcvmw7.png" alt="correct slim scroll" width="800" height="584"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As a countermeasure against unleashing erratic scrolls onto the production stage, we developed a simple yet effective technique: Set scroll visibility to 'always' in Mac settings. Voila! This proved to be an efficient stopgap solution to trim down such issues in production. Who said all solutions must be complex?&lt;/p&gt;

&lt;p&gt;Also, credit to my teammate Alex for using Firefox when the rest of us were sailing on the Chrome ship. Thanks to this, many pesky CSS bugs met their end.&lt;/p&gt;

&lt;p&gt;So, here's a pro tip: use different browsers. Sure, you can opt for a complex solution like setting up a browser stack for your CSS issues, but it's not the feasible choice for every team. However, testing your project in two or three major browsers that your client uses can drastically help you nip issues in the bud.&lt;/p&gt;

&lt;p&gt;But hey, it's not just my team battling these scroll-based outlaws. As we discovered, the world of coding is &lt;a href="https://i.ibb.co/0Fg5X6R/scroll.gif"&gt;a lot more scroll-stricken&lt;/a&gt; than we had thought.&lt;/p&gt;


&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; When to upgrade?
&lt;/h2&gt;

&lt;p&gt;To upgrade, or not to upgrade – that is indeed one of our biggest questions in programming. The question of 'When to upgrade' has been a long-standing challenge. Essentially, it comes down to two main factors:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Developers are always keen on keeping step with the newest versions of libs and frameworks.&lt;/li&gt;
&lt;li&gt;Managers are motivated to roll out the latest product versions to clients.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now, let's delve right in and weigh the pros and cons in this see-saw of upgrading:&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Pros:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Performance Boost&lt;/strong&gt;: Upgrades can enhance your software's performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;New Features&lt;/strong&gt;: Upgrades often come with exciting new features, upping your tech game.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bug Fixes&lt;/strong&gt;: If you've been struggling with certain bugs, upgrades might be your savior.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Cons:&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Potential Bugs&lt;/strong&gt;: Every new addition comes with the risk of bugs. Bug fixes can be time-consuming and lower your confidence in the new code.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Breaking Changes&lt;/strong&gt;: Upgrades are often tagged along with breaking changes. For instance, with Node 16 support being dropped by Angular 17, the adaptation time considerably increases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Applying upgrades can undoubtedly bring many benefits, but they can also be a Pandora's box of unforeseen problems. You might wonder – How much work would it take to transition from Node 16 to Node 18 in a project? A simple version change, or a time-consuming search for the correct versions of all packages?&lt;/p&gt;

&lt;p&gt;Personally, I'm on the cautious side when it comes to upgrades. However, some teammates are keen on them, and together, we've found a balance to keep our software updated, or at least close to the latest versions with minimal disruptions.&lt;/p&gt;
&lt;h3&gt;
  
  
  This is the case now, but before…
&lt;/h3&gt;

&lt;p&gt;Backtracking a few years, we had an intriguing encounter with a new client, keen on deploying our software (&lt;a href="https://uibakery.io/"&gt;https://uibakery.io/&lt;/a&gt;) on-premise. We provided them with a deployment guide, and surprisingly, they came back with a security report pointing out hundreds of issues, with tens of them as critical vulnerabilities!&lt;/p&gt;

&lt;p&gt;Interestingly, all the major problems in our images could have been fixed easily with a regular update – potentially saving us from losing the client! This incident made us realize the power of staying updated. Since then, we've made it a point to perform security scans before any rollout.&lt;/p&gt;

&lt;p&gt;In conclusion, finding the right time to upgrade is all about striking a balance and understanding your project's specific needs.&lt;/p&gt;


&lt;h2&gt;
  
  
  Naming things
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Any fool can write code that a computer can understand. Good programmers write code that humans can understand.&lt;br&gt;
—- Martin Fowler&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;One of the simplest, yet crucial undertakings in any coding project, is to appropriately name things. Seeing is believing, so let's look at two bites of code:&lt;/p&gt;

&lt;p&gt;The first one, as you'll agree is a riddle, demanding a thorough read to decrypt its purpose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LN&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="no"&gt;B&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;s&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Harry Potter"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;s&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lord of the Rings"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;l&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;B&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="no"&gt;B&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;s&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Book added: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;l&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Book List:"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;util&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entrySet&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ID: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKey&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;", Title: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The second one, in contrast, is reasonably transparent - a mere skim leads to an understanding of its functioning.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LibraryManager&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;Library&lt;/span&gt; &lt;span class="n"&gt;library&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Library&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addBook&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Harry Potter"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addBook&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Lord of the Rings"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;library&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;displayBookList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Library&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;bookMap&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nc"&gt;Library&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;bookMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;HashMap&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;addBook&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;bookMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;put&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Book added: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;

    &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;displayBookList&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Book List:"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Map&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Entry&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Integer&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bookMap&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;entrySet&lt;/span&gt;&lt;span class="o"&gt;())&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"ID: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getKey&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;", Title: "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;entry&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getValue&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
        &lt;span class="o"&gt;}&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Appropriate naming is not just important in code. In fact, it’s often even more vital during team discussions. In my team, during discussions, we from time to time find ourselves deeply involved in intense arguing. Eventually, we come to understand that we all agree, but we have been using different terms to express our ideas.&lt;/p&gt;

&lt;p&gt;In my view, assigning clear, descriptive names, and spreading these terms consistently across the team is one of the most crucial tasks in any project.&lt;/p&gt;

&lt;p&gt;Why is this still a thorn in the side for many? The answer's simple: there isn't an automated linter/test/validator that can certify your naming conventions. Each member of your team comes with a diverse background, varied experiences, and unique views regarding variable names. To create harmony among these different factors takes a lot of time. If anyone knows an easy solution for this, I'd really like to hear it!&lt;/p&gt;




&lt;h2&gt;
  
  
  &lt;a&gt;&lt;/a&gt; N+1
&lt;/h2&gt;

&lt;p&gt;A few months ago, my colleague Vlad, also the CEO, summoned me to review a newly raised pull request (yes, our CEO is coding and it's another pain in the ass 🙃). The said PR is meant to augment how our clients manage their users on our platform. We work with Spring Boot in the backend, and this project update included a large SQL query that was about 150 lines long. Here's how our discussion went:&lt;/p&gt;

&lt;p&gt;Nik: Vlad, great work on your PR. However, using 150 lines of SQL might be too complex, especially for those who see it for the first time. If you're busy with CEO work and we need to handle it, it could be tough. How about we try doing it in Java instead?&lt;/p&gt;

&lt;p&gt;Vlad: Sure, Nik. I foresaw some performance optimization, but I'll go with your judgment.&lt;/p&gt;

&lt;p&gt;Nik: Do we have clients to whom this change could impact significantly?&lt;/p&gt;

&lt;p&gt;Vlad: Not yet, but the scope could unfold.&lt;/p&gt;

&lt;p&gt;Nik: Exactly. Let's rewrite it in Java to make it easier to read. If we face problems that need SQL, we can change our approach later.&lt;/p&gt;

&lt;p&gt;Vlad: Sounds good.&lt;/p&gt;

&lt;p&gt;Henceforth, the PR was rolled out to production without a hitch, until, of course, we began expanding it to our on-premises clients.&lt;/p&gt;

&lt;p&gt;One of the on-premises clients had already invited a significant user base. However, the new user-management page, introduced by Vlad, took 3+ minutes to load 🥳. Of course, we had then run into the N+1 problem. I was like:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcv2sooryvl6231l6g8hd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcv2sooryvl6231l6g8hd.png" alt="facepalm" width="350" height="263"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The N+1 problem happens when you first make one query to get a group of main items (+1), and then you make additional queries to get related details for each of these main items (N). For N objects, you end up unleashing N+1 queries, akin to ordering several pizzas and then asking separately for each topping's ingredients!&lt;/p&gt;

&lt;p&gt;Though the N+1 issue is relatively general, it became all too familiar to me with ORMs (Object-relational mappings), and REST-like APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;ORM&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Imagine you have a fancy ORM (Object-Relational Mapping) tool. It fetches data from your database and simplifies your life until the N+1 problem steals the show. Ironically, ORMs mostly default to lazy loading – they grab only the primary object first, picking the associated objects only when required. It sounds apt until you're in an N+1 scenario. Suddenly, your database is overworking, and you're left pondering: "Did I just order a pizza, or did I start baking the dough myself?"&lt;/p&gt;

&lt;p&gt;Let's take a look at Hibernate, an ORM tool I often use for examples. Imagine we have two things: Author and Book. These represent authors and their books in a library. In our example, each Book is connected to an Author using a special link called &lt;code&gt;@OneToMany(mappedBy = "author")&lt;/code&gt;. This shows the relationship between the authors and their books.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Author&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@OneToMany&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mappedBy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"author"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Book&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Entity&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Book&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Id&lt;/span&gt;
    &lt;span class="nd"&gt;@GeneratedValue&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strategy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GenerationType&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;IDENTITY&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Long&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="n"&gt;title&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

    &lt;span class="nd"&gt;@ManyToOne&lt;/span&gt;
    &lt;span class="nd"&gt;@JoinColumn&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"author_id"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;Author&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Suppose we aim at fetching a list of authors and their books through Hibernate. We might take this route:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Author&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;authors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entityManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT a FROM Author a"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Author&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getResultList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Author&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;authors&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// This triggers the N+1 problem!&lt;/span&gt;
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Book&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;books&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;author&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getBooks&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Do something with the books&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, Hibernate starts loading authors eagerly. However, it doesn't immediately fetch their corresponding books. As we pivot through the &lt;code&gt;getBooks()&lt;/code&gt; method for each author, Hibernate charges forth with separate SQL queries for each author to load their books. This encapsulates the quintessence of the N+1 problem.&lt;/p&gt;

&lt;p&gt;But don't worry, &lt;em&gt;fetch joins&lt;/em&gt; can adjust our query to quickly get both the related books and their authors together:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Author&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;authors&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;entityManager&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createQuery&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SELECT DISTINCT a FROM Author a LEFT JOIN FETCH a.books"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Author&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;class&lt;/span&gt;&lt;span class="o"&gt;).&lt;/span&gt;&lt;span class="na"&gt;getResultList&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, Hibernate collates both authors and their books in a single query, exiling the N+1 problem.&lt;/p&gt;

&lt;p&gt;However, dealing with large datasets may not be easy, and debugging can be elusive if you don't know your way around. When facing performance issues around the database, my go-to step is to fully enable SQL logging. There, I spotted numerous queries, unraveling the N+1 problem at hand.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;REST-like APIs&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Now, onto the REST-like API territory. Visualize an API that returns a list of entities (like superheroes), each retaining a list of superpowers. Making an API request to get a list of heroes could trigger the N+1 problem. You obtain the list but would have to make an additional request for each hero's superpowers. It's like attending a superhero meet-and-greet, but each hero narrates their origin plot individually, and efficiency takes a hit.&lt;/p&gt;

&lt;p&gt;Here's where GraphQL shines, enabling you to specify what data you require and its structure, avoiding excessive requests. Like ordering a combo meal instead of separate dishes, GraphQL encapsulates your request as a single comprehensive entity.&lt;/p&gt;

&lt;p&gt;There are different ways to solve the problem, not just with GraphQL. Options like &lt;a href="https://jsonapi.org/"&gt;JSON:API&lt;/a&gt; work too. But mostly, GraphQL has become the most popular choice for this.&lt;/p&gt;

&lt;p&gt;In summary, N+1 could potentially be the villain in the realm of programming, but gallant tools like GraphQL could come to the rescue and restore order to this digital pandemonium. Be wise, choose your heroes wisely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Dates
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlknya9hf59k02iz8ou1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqlknya9hf59k02iz8ou1.png" alt="how to use dates in Javascript" width="720" height="891"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Yes, once in a while, we all get slapped by the confounding inconsistencies of 'Dates.'&lt;/p&gt;

&lt;p&gt;Regrettably, I don't have an engaging story to share, but I do have this list of date-related puzzles that left me scratching my head last year:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Varying Formats: No, 'Dates' are not a fan of uniformity. They stroll into your system bearing different getups, sometimes even within the same database or API.&lt;/li&gt;
&lt;li&gt;Time Zone Tango: The dance between different time zones for client and server can get quite confusing.&lt;/li&gt;
&lt;li&gt;The World Clock: Imagine dealing with clients operating in various time zones!&lt;/li&gt;
&lt;li&gt;The Hour Offset Conundrum: Not all time zones proudly wear the one-hour badge.&lt;/li&gt;
&lt;li&gt;Server-Time Zone Mismatch: The servers wandering in various time zones while the database sticks to its own is chaotic.&lt;/li&gt;
&lt;li&gt;Leap Year and Leap Second: Because 'Dates' like to jump around a bit.&lt;/li&gt;
&lt;li&gt;The Calendar Conversion: Converting 'Dates' between different calendars (like Gregorian, Julian, Lunar) is a formidable task.&lt;/li&gt;
&lt;li&gt;Time Zone Twisters: Handling time zones with irregular offsets or historical changes is nothing short of a rollercoaster ride.&lt;/li&gt;
&lt;li&gt;Distributed Systems or Microservices: Managing time zones in these scenarios typically calls for some hair-pulling.&lt;/li&gt;
&lt;li&gt;On-Premises Deployments: Valid time becomes a puzzle when dealing with clients' on-premises deployments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dealing with dates in programming is much more complicated than it seems. It's just one part of the bigger challenge. Working with dates can be very confusing. In my experience, problems with dates are more difficult than issues with caching or naming. Or at least more irritating.&lt;/p&gt;




&lt;h2&gt;
  
  
  Finally
&lt;/h2&gt;

&lt;p&gt;Finally, I want to say that all those problems are generally solvable - you can solve them in each individual case - you can name one variable properly, you can deal with scrolls on individual pages, you can design how you work with dates in your system and you can make sure that this exact controller method doesn’t have N+1 problem.&lt;/p&gt;

&lt;p&gt;However, solving them in general is too hard and I don't think is possible - you can’t somehow force your team to name all the variables, functions, and classes properly. You can’t make one simple setup and make sure that all the scrolls in the system are always identical. You can’t add a few tests and make sure that dates in your system work correctly, necessarily there will be someone who will skip your rules and accidentally break the system.&lt;/p&gt;

&lt;p&gt;What can we do here? We’re trying to use the Pareto rule and get 80% of results using 20% of the time - doing small simple steps to prevent most of the issues. Doing code reviews, doing hacks as explained in the scrolls section (enabling scrolls everywhere), doing testing for crucial flows, etc. We know we can't catch everything, so there might still be problems when it's actually deployed to production.&lt;/p&gt;

&lt;h2&gt;
  
  
  PS
&lt;/h2&gt;

&lt;p&gt;This is a list of programming issues that I find particularly irritating. What are the coding challenges that annoy you the most? Please share your thoughts with me!&lt;/p&gt;

&lt;h2&gt;
  
  
  PPS
&lt;/h2&gt;

&lt;p&gt;Hit a comment if you like the off-by-1 problem explanation.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>challenge</category>
    </item>
    <item>
      <title>Agile Angular modules configuration</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Tue, 10 Nov 2020 13:50:54 +0000</pubDate>
      <link>https://dev.to/nikpoltoratsky/agile-angular-modules-configuration-i7j</link>
      <guid>https://dev.to/nikpoltoratsky/agile-angular-modules-configuration-i7j</guid>
      <description>&lt;p&gt;Follow me on Twitter at &lt;a href="http://twitter.com/nikpoltoratsky"&gt;@NikPoltoratsky&lt;/a&gt; | Subscribe to the &lt;a href="https://motivated-musician-5947.ck.page/bd54abc356"&gt;Newsletter&lt;/a&gt; | Originally published on &lt;a href="https://howtomake.software/blog/agile-angular-module-with-dependency-injection"&gt;howtomake.software&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;If you already built a few Angular applications it might be you already spotted how it may be tricky to build easily configurable modules.&lt;/p&gt;

&lt;p&gt;I mean, if you're building a reusable module it might be you need to configure it somehow. And if this module contains different entities (multiple components, services, directives, and pipes) it will be hard to configure them separately. It would be better to configure the whole module in one place.&lt;/p&gt;

&lt;p&gt;For example, let's take a look at the Angular material dialog.&lt;/p&gt;

&lt;p&gt;The angular material dialog contains multiple entities - components and services. And it provides us with the single point of configuration - &lt;code&gt;MAT_DIALOG_DEFAULT_OPTIONS&lt;/code&gt; is the Dependency Injection (DI) token that allows us to configure all the material dialogs at the application at one place.&lt;/p&gt;

&lt;p&gt;In this article, I'll be talking about how to configure Angular components and services using the Dependency Injection concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents:
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;How we use DI most of all&lt;/li&gt;
&lt;li&gt;Putting data in the DI&lt;/li&gt;
&lt;li&gt;Building configurable modules&lt;/li&gt;
&lt;li&gt;Using forRoot/forFeature for module configuration&lt;/li&gt;
&lt;li&gt;Why it might be not a good idea?&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  How we use DI most of all
&lt;/h2&gt;

&lt;p&gt;The main idea of DI is to provide dependencies for different entities - components, services, modules, and so on.&lt;br&gt;
The most frequent usage of DI in Angular is to inject services into components.&lt;/p&gt;

&lt;p&gt;In that case, you're creating a service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyService&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, you're using it in component, easy as that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;MyService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Even though this is the most popular way to use DI we have other ways to use it. Let's explore how to use DI for system configuration.&lt;br&gt;
We're going to learn about system configuration but first things first, so, let's start with &lt;strong&gt;Injection Tokens&lt;/strong&gt; 🥳.&lt;/p&gt;
&lt;h2&gt;
  
  
  Putting data in the DI
&lt;/h2&gt;

&lt;p&gt;Injection Tokens is the Angular concept that allows you to &lt;strong&gt;put&lt;/strong&gt; something in the DI system. For instance, you want to provide a configuration object for your app.&lt;br&gt;
First of all, we need to create it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;InjectionToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This is a configuration object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, we need to provide it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, you can use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CONFIG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// will be 'bar'&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;Injection tokens allow us to &lt;strong&gt;put&lt;/strong&gt; some data inside the DI container and then consume it everywhere. Using injection tokens we can build agile configuration systems for our applications. Let's do that! 🌈&lt;/p&gt;

&lt;h2&gt;
  
  
  Building configurable modules
&lt;/h2&gt;

&lt;p&gt;Let's assume we have to build a component, for instance - dialog component. It will have tons of configuration options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;MatDialogConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;D&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;viewContainerRef&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ViewContainerRef&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;id&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;role&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;DialogRole&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;dialog&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;panelClass&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;hasBackdrop&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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="nl"&gt;backdropClass&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;disableClose&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;minWidth&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;minHeight&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxWidth&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;80vw&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;maxHeight&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;DialogPosition&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;D&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;direction&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Direction&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;ariaDescribedBy&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;ariaLabelledBy&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;ariaLabel&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;autoFocus&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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="nl"&gt;restoreFocus&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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="nl"&gt;scrollStrategy&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ScrollStrategy&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;closeOnNavigation&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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="nl"&gt;componentFactoryResolver&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;ComponentFactoryResolver&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;Lot's of configurations here 🙃. And it's impossible to copy/paste it each time when you're using the dialog in your application.&lt;br&gt;
Looks like it would be awesome to install global configuration first of all and then just overwrite at the place when we're using the dialog.&lt;br&gt;
How to do that? Frankly speaking, quite easy:&lt;/p&gt;

&lt;p&gt;First of all, we're creating an injection token that'll allow us to provide configuration for our dialog component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;DIALOG_CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;InjectionToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;This is a configuration object for our dialog component&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in any place where we need it, we're just using it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;DialogComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DIALOG_CONFIG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;DialogService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(@&lt;/span&gt;&lt;span class="nd"&gt;Inject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DIALOG_CONFIG&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use it anywhere you need it. When we're using dialog we're providing configuration at the root level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DIALOG_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{...}&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then, all the instances of the &lt;strong&gt;dialog&lt;/strong&gt; will share the same configuration out of the box.&lt;/p&gt;

&lt;p&gt;However, this approach requires the user of the library to know about too many concepts. Generally, the user ought to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;import the module&lt;/li&gt;
&lt;li&gt;provide configuration through the &lt;code&gt;DIALOG_CONFIG&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;import and use the required services and components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But we have a solution that helps to reduce the number of concepts the user ought to know. Let's hide &lt;code&gt;DIALOG_CONFIG&lt;/code&gt; from the user but still keep the ability to provide it outside.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using forRoot/forFeature for module configuration
&lt;/h2&gt;

&lt;p&gt;I bet you already saw and used the &lt;code&gt;forRoot&lt;/code&gt; modules configuration with the &lt;code&gt;RouterModule&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;forRoot&lt;/code&gt; - is a convention that allows the authors of modules to provide a simple interface for module configuration. Let's see how to make it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;declarations&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// all the components and directive are declared here&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;DialogModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="nx"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;ModuleWithProviders&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DialogModule&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;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;ngModule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DialogModule&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DIALOG_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above we have a &lt;code&gt;DialogModule&lt;/code&gt; that declares all the components, directives, services, and other entities.&lt;/p&gt;

&lt;p&gt;Also, it has a static &lt;code&gt;forRoot&lt;/code&gt; method that returns &lt;code&gt;ModuleWithProviders&lt;/code&gt; - an object with declared &lt;code&gt;ngModule&lt;/code&gt; and all the providers that ought to be declared at the root level.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This is the reason why it's called &lt;code&gt;forRoot&lt;/code&gt;. It's supposed to be called at the &lt;strong&gt;root level&lt;/strong&gt; only. Otherwise, you might spot problems because of multiple &lt;code&gt;forRoot&lt;/code&gt; calls.&lt;/p&gt;

&lt;p&gt;Instead, modules authors provide us with &lt;code&gt;forFeature&lt;/code&gt; level if their modules can be reconfigured at the &lt;strong&gt;feature level&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;forRoot&lt;/code&gt; method receives &lt;code&gt;config&lt;/code&gt; - the configuration object that will be provided at the root level and will be available for all the entities.&lt;/p&gt;

&lt;p&gt;Then, we're using it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// now we can do this:&lt;/span&gt;
    &lt;span class="nx"&gt;DialogModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;({}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;providers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// instead of this:&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;provide&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;DIALOG_CONFIG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;useValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see above, this approach makes modules configuration seamless! And the user doesn't need to think about providing something, just calling the function! 😱&lt;/p&gt;

&lt;p&gt;Looks cool, right? 🥳 Until it's not.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it's not a good idea?
&lt;/h2&gt;

&lt;p&gt;It's an implicit approach. The problem is that if you're providing configuration somewhere in another place rather than in place when you're using it'll be hard to understand by the reader of the code.&lt;/p&gt;

&lt;p&gt;Let's return to the example with the dialog. So, here I have a root configuration that defines some application wide dialog configurations:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;DialogModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forRoot&lt;/span&gt;&lt;span class="p"&gt;({})],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, in different feature modules I do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// Providing another `closeIcon`&lt;/span&gt;
    &lt;span class="nx"&gt;DialogModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forFeature&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;closeIcon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;flower&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;FooFeatureModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="c1"&gt;// Providing another `closeIcon`&lt;/span&gt;
    &lt;span class="nx"&gt;DialogModule&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forFeature&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;closeIcon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;BarFeatureModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, I'm just using the dialog:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;MyComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;showDialog&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dialog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cool! Then, I'm returning to this code in a year and I need to check why do I have some configurations at the dialog? I'm checking the place where I'm calling and what do I see? You're right! Nothing! No configuration here. Hmm, then I have to go to my feature module and then to the root module. So, I need to check three places instead of one.&lt;/p&gt;

&lt;p&gt;Moreover here, what if I didn't see this module before? What if I have no idea how this configuration works? In that case, it'll be pretty hard to figure out what's going on in the app and which configuration was taken into the account.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't overuse that approach. It'll help you configuring applications but overusing that idea will lead to hell. 😭&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;So, as you can see here, Dependency Injection is a powerful concept that can be used not only for services injection but also for configurations injection. It has many many more usages but we'll take a look at them in other articles.&lt;/p&gt;

&lt;p&gt;Follow me on twitter to be notified about more cool content &lt;a href="http://twitter.com/nikpoltoratsky"&gt;http://twitter.com/nikpoltoratsky&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>angular</category>
      <category>di</category>
      <category>rxjs</category>
      <category>typescript</category>
    </item>
    <item>
      <title>Draggable Table with Angular CDK</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Tue, 25 Aug 2020 13:26:27 +0000</pubDate>
      <link>https://dev.to/nikpoltoratsky/draggable-table-with-angular-cdk-47i3</link>
      <guid>https://dev.to/nikpoltoratsky/draggable-table-with-angular-cdk-47i3</guid>
      <description>&lt;p&gt;&lt;strong&gt;This article is originally published on &lt;a href="https://howtomake.software/course/angular-cdk-crash-course"&gt;howtomake.software&lt;/a&gt;.&lt;/strong&gt; &lt;/p&gt;

&lt;h2&gt;
  
  
  What are we going to build?
&lt;/h2&gt;

&lt;p&gt;In this article, I'm going to show you how to build a table with an ability to rearrange rows in it. 👇&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cwn97pMB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://howtomake.software/assets/blog/draggable-table-with-angular-cdk/demo.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cwn97pMB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://howtomake.software/assets/blog/draggable-table-with-angular-cdk/demo.gif" alt="demo" width="600" height="478"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What do we need for that?
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Angular CDK
&lt;/h3&gt;

&lt;p&gt;All the functionalities we need for the draggable table are bundled inside the Angular CDK package. Let's install it first of all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; @angular/cdk
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the Angular CDK package is installed in your project it's a time to understand what exactly we're going to use from the package.&lt;/p&gt;

&lt;h3&gt;
  
  
  Angular CDK Table Module
&lt;/h3&gt;

&lt;p&gt;Since we're building a draggable &lt;strong&gt;table&lt;/strong&gt;, the first thing we need is &lt;strong&gt;table&lt;/strong&gt; 🙄. Angular CDK Table Module allows us to build powerful tables easily. Let's take a look at how to do that.&lt;/p&gt;

&lt;p&gt;First of all, we ought to import the Angular CDK Table into the &lt;code&gt;AppModule&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NgModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CdkTableModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular/cdk/table&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CdkTableModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;CdkTableModule&lt;/code&gt; allows us to use basic tables primitive directives: &lt;code&gt;cdk-table&lt;/code&gt;, &lt;code&gt;cdkColumnDef&lt;/code&gt;, &lt;code&gt;cdk-header-cell&lt;/code&gt;, &lt;code&gt;cdk-cell&lt;/code&gt;, etc. Let's discuss, how to use them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create Table
&lt;/h3&gt;

&lt;p&gt;We need to create a table itself. Let's add a plain HTML table and mark it as the Angular CDK Table using &lt;code&gt;cdk-table&lt;/code&gt; directive:&lt;br&gt;
&lt;/p&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;table&lt;/span&gt; &lt;span class="na"&gt;cdk-table&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to configure the table structure. We can do so using directives provided by the &lt;code&gt;CdkTableModule&lt;/code&gt;. Let's configure each piece one by one:&lt;/p&gt;

&lt;h4&gt;
  
  
  Header row configuration
&lt;/h4&gt;

&lt;p&gt;Header row can be configured using &lt;code&gt;cdk-header-row&lt;/code&gt;. This directive will let &lt;code&gt;cdk-table&lt;/code&gt; understand that it's a template for the header row. Then, we're adding a &lt;code&gt;cdkHeaderRowDef&lt;/code&gt; directive. It receives a list of columns to be shown.&lt;br&gt;
&lt;/p&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;tr&lt;/span&gt;
  &lt;span class="na"&gt;cdk-header-row&lt;/span&gt;
  &lt;span class="na"&gt;*cdkHeaderRowDef=&lt;/span&gt;&lt;span class="s"&gt;"['position', 'name', 'weight', 'symbol']"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Table row configuration
&lt;/h4&gt;

&lt;p&gt;A table row can be configured using &lt;code&gt;cdk-row&lt;/code&gt;. This directive will let &lt;code&gt;cdk-table&lt;/code&gt; understand that it's a template for the table row. Then, we're adding a &lt;code&gt;cdkHeaderRowDef&lt;/code&gt; directive. It receives a list of columns to be shown.&lt;br&gt;
&lt;/p&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;tr&lt;/span&gt;
  &lt;span class="na"&gt;cdk-row&lt;/span&gt;
  &lt;span class="na"&gt;*cdkRowDef=&lt;/span&gt;&lt;span class="s"&gt;"let row; columns: ['position', 'name', 'weight', 'symbol'];"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Table cells configuration
&lt;/h4&gt;

&lt;p&gt;Now, it's a time to configure table cells:&lt;br&gt;
&lt;/p&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;ng-container&lt;/span&gt; &lt;span class="na"&gt;cdkColumnDef=&lt;/span&gt;&lt;span class="s"&gt;"position"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;cdk-header-cell&lt;/span&gt; &lt;span class="na"&gt;*cdkHeaderCellDef&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; No. &lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;cdk-cell&lt;/span&gt; &lt;span class="na"&gt;*cdkCellDef=&lt;/span&gt;&lt;span class="s"&gt;"let element"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; {{element.position}} &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;cdkColumnDef=&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;cdk-header-cell&lt;/span&gt; &lt;span class="na"&gt;*cdkHeaderCellDef&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Name &lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;cdk-cell&lt;/span&gt; &lt;span class="na"&gt;*cdkCellDef=&lt;/span&gt;&lt;span class="s"&gt;"let element"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; {{element.name}} &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;cdkColumnDef=&lt;/span&gt;&lt;span class="s"&gt;"weight"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;cdk-header-cell&lt;/span&gt; &lt;span class="na"&gt;*cdkHeaderCellDef&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Weight &lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;cdk-cell&lt;/span&gt; &lt;span class="na"&gt;*cdkCellDef=&lt;/span&gt;&lt;span class="s"&gt;"let element"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; {{element.weight}} &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;ng-container&lt;/span&gt; &lt;span class="na"&gt;cdkColumnDef=&lt;/span&gt;&lt;span class="s"&gt;"symbol"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;th&lt;/span&gt; &lt;span class="na"&gt;cdk-header-cell&lt;/span&gt; &lt;span class="na"&gt;*cdkHeaderCellDef&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; Symbol &lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;td&lt;/span&gt; &lt;span class="na"&gt;cdk-cell&lt;/span&gt; &lt;span class="na"&gt;*cdkCellDef=&lt;/span&gt;&lt;span class="s"&gt;"let element"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt; {{element.symbol}} &lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ng-container&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The most important part here is &lt;code&gt;cdkColumnDef&lt;/code&gt;. It says which column we're configuring. As you remember, we just told the Angular CDK Table that we'll have the following columns in the table: &lt;code&gt;['position', 'name', 'weight', 'symbol']&lt;/code&gt;. Now we're using &lt;code&gt;cdkColumnDef="name"&lt;/code&gt; to tell the table which column we're configuring here. We have pretty similar configurations for all columns. Let's dive inside columns templates.&lt;/p&gt;

&lt;p&gt;Inside each column definition, we have two lines: one for the header cell or &lt;em&gt;th&lt;/em&gt; and one for the row cell or &lt;em&gt;td&lt;/em&gt;.&lt;br&gt;
&lt;/p&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;th&lt;/span&gt; &lt;span class="na"&gt;cdk-header-cell&lt;/span&gt; &lt;span class="na"&gt;*cdkHeaderCellDef&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Name&lt;span class="nt"&gt;&amp;lt;/th&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This line configures a header cell for the &lt;em&gt;name&lt;/em&gt; column. It tells the table that it's a header cell via &lt;code&gt;cdk-header-cell&lt;/code&gt; directive. And marks it as a cell template with &lt;code&gt;*cdkHeaderCellDef&lt;/code&gt;.&lt;br&gt;
&lt;/p&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;td&lt;/span&gt; &lt;span class="na"&gt;cdk-cell&lt;/span&gt; &lt;span class="na"&gt;*cdkCellDef=&lt;/span&gt;&lt;span class="s"&gt;"let element"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{{element.name}}&lt;span class="nt"&gt;&amp;lt;/td&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While this line configures how the table row cell will look like. &lt;code&gt;cdk-cell&lt;/code&gt; marks this element as a table cell. And &lt;code&gt;*cdkCellDef="let element"&lt;/code&gt; directive marks it as a template and provides the link to the active row &lt;code&gt;element&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But where we'll get those elements? Right now we have only the template and nothing similar to data! Hmm. The Angular CDK Table operates with the concept of &lt;em&gt;datasource&lt;/em&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Datasource
&lt;/h3&gt;

&lt;h4&gt;
  
  
  What is Angular CDK Table data source
&lt;/h4&gt;

&lt;p&gt;The data source concept describes how you can provide data to the Angular CDK Table. It can be done in three ways:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;The simplest way is to use a plain javascript array. It ought to contain objects. And in that case, each object represents one table row.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using &lt;code&gt;Observable&lt;/code&gt;. In that case, you ought to provide a stream of arrays. The table will rerender each time that &lt;code&gt;Observable&lt;/code&gt; emits a new array. (We'll use that approach for the data source in this tutorial).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Using &lt;code&gt;DataSource&lt;/code&gt; object that implements &lt;code&gt;DataSource&lt;/code&gt; interface that contains &lt;code&gt;connect&lt;/code&gt;/&lt;code&gt;disconnect&lt;/code&gt; functions. This approach is useful for more complex scenarios. Especially in cases when you need to clean up our data stream. This can be done using &lt;code&gt;disconnect&lt;/code&gt; functionality.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  How to attach data to the table?
&lt;/h4&gt;

&lt;p&gt;First of all let's create an array with data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;PeriodicElement&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hydrogen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;1.0079&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;H&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Helium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;4.0026&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;He&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Lithium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;6.941&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Li&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Beryllium&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;9.0122&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Be&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Boron&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;10.811&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;symbol&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;B&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we ought to push that data into the subject. That's required since we're going to change the order of rows during the drag and drop.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;datasource&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&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;After that, when we have a stream of data we ought to connect it to the table:&lt;br&gt;
&lt;/p&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;table&lt;/span&gt; &lt;span class="na"&gt;[dataSource]=&lt;/span&gt;&lt;span class="s"&gt;"dataSource"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NRX5pimV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://howtomake.software/assets/blog/draggable-table-with-angular-cdk/table.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NRX5pimV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://howtomake.software/assets/blog/draggable-table-with-angular-cdk/table.png" alt="Table demo" width="800" height="566"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that's it. Now we have a table and a data source connected to it. Now it's a time to make it draggable!&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding Drag &amp;amp; Drop
&lt;/h2&gt;

&lt;p&gt;All the functionalities we need for the drag and drop are bundled inside the Angular CDK DragDrop module. So, let's import it first of all:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;NgModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;DragDropModule&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/cdk/drag-drop&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;NgModule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;imports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;DragDropModule&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppModule&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;DragDropModule&lt;/code&gt; is installed it allows us to use &lt;code&gt;cdkDrag&lt;/code&gt; and &lt;code&gt;cdkDropList&lt;/code&gt; directives inside our templates to make elements draggable. Let's see how it works.&lt;/p&gt;

&lt;h3&gt;
  
  
  cdkDrag
&lt;/h3&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;tr&lt;/span&gt; &lt;span class="na"&gt;cdk-row&lt;/span&gt; &lt;span class="na"&gt;*cdkRowDef=&lt;/span&gt;&lt;span class="s"&gt;"let row;"&lt;/span&gt; &lt;span class="na"&gt;cdkDrag&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a table row we defined a few minutes ago. But now I added a &lt;code&gt;cdkDrag&lt;/code&gt; directive here. This directive makes an element draggable.&lt;/p&gt;

&lt;h3&gt;
  
  
  cdkDropList
&lt;/h3&gt;

&lt;p&gt;The next step is to define the container for draggable elements. Since in our case we're going to rearrange table rows, that means our draggable elements container is our table:&lt;br&gt;
&lt;/p&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;table&lt;/span&gt; &lt;span class="na"&gt;cdk-table&lt;/span&gt; &lt;span class="na"&gt;cdkDropList&lt;/span&gt; &lt;span class="na"&gt;(cdkDropListDropped)=&lt;/span&gt;&lt;span class="s"&gt;"drop($event)"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/table&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've just added &lt;code&gt;cdkDropList&lt;/code&gt; directive here. It marks the table as a draggable elements container and allows us to intercept &lt;em&gt;drop&lt;/em&gt; events using &lt;code&gt;cdkDropListDropped&lt;/code&gt; directive output. So, when the user releases an element somewhere on the table we'll receive that &lt;em&gt;drop&lt;/em&gt; event. Then, we'll be able to react on it and rearrange the data in the table's data source.&lt;/p&gt;

&lt;p&gt;So, as you can notice above I've added &lt;code&gt;drop&lt;/code&gt; callback to the &lt;code&gt;cdkDropListDropped&lt;/code&gt; event. Let's implement it to make our table finally rearrangeable!!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;CdkDragDrop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;moveItemInArray&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/cdk/drag-drop&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;drop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CdkDragDrop&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&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="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// Rearrange the data in the array&lt;/span&gt;
    &lt;span class="nx"&gt;moveItemInArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;previousIndex&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;currentIndex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;// Publish a new version of the data into the datasource&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dataSource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;([...&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What's going on here? We're just receiving a &lt;code&gt;CdkDragDrop&lt;/code&gt; event. It contains all the required information to move the item. It has a &lt;code&gt;previousIndex&lt;/code&gt; and a &lt;code&gt;currentIndex&lt;/code&gt; of the item that was moved visually by the user. Then, we can move it from the previous place to the new place using the &lt;code&gt;moveItemInArray&lt;/code&gt; function provided by the Angular CDK DragDrop module.&lt;/p&gt;

&lt;p&gt;And finally, we're just publishing a new version of data to the table! Easy as that! And here is the result 👇&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://stackblitz.com/edit/draggable-table?" width="100%" height="500"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Recap
&lt;/h2&gt;

&lt;p&gt;At this tutorial, you learned how to make rearrangeable tables in Angular using Angular CDK Tables and DragDrop modules. I hope you get all the details and liked the article. If you have any questions, please, let me know on &lt;a href="https://twitter.com/nikpoltoratsky"&gt;twitter&lt;/a&gt;, I'll try to help you.&lt;/p&gt;

&lt;p&gt;If you're interested in more content about Angular CDK, follow me on &lt;a href="https://twitter.com/nikpoltoratsky"&gt;twitter&lt;/a&gt; and &lt;a href="https://motivated-musician-5947.ck.page/bd54abc356"&gt;subscribe to my newsletter&lt;/a&gt;🔥&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
    </item>
    <item>
      <title>Why reducer is reducer?</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Wed, 06 May 2020 10:54:36 +0000</pubDate>
      <link>https://dev.to/nikpoltoratsky/why-reducer-is-reducer-bcl</link>
      <guid>https://dev.to/nikpoltoratsky/why-reducer-is-reducer-bcl</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://howtomake.software/blog/why-reducer-is-reducer"&gt;https://howtomake.software&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this article, I'm introducing my mental model of modern state management.&lt;/p&gt;

&lt;p&gt;More exactly I'm talking on how &lt;a href="https://ngrx.io"&gt;ngrx&lt;/a&gt; works, why reducer is a reducer, and how it&lt;br&gt;
is related to the JavaScript's array reduce method. All the statements here will likely be true&lt;br&gt;
for any state management solution using redux concepts. So, if you're using Redux, you're welcome 🤓.&lt;/p&gt;
&lt;h2&gt;
  
  
  At this article we'll cover:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;What is ngrx?&lt;/li&gt;
&lt;li&gt;What is array reduce?&lt;/li&gt;
&lt;li&gt;Understanding reduce concept&lt;/li&gt;
&lt;li&gt;So, why reducer is reducer?&lt;/li&gt;
&lt;/ul&gt;



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

&lt;p&gt;If you have no experience with ngrx or other redux like state management solutions, I would personally recommend you to&lt;br&gt;
learn about them first. I would suggest you start at the &lt;a href="https://ngrx.io/guide/store"&gt;ngrx getting started guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, I'll still cover how it works briefly. Here is a diagram from the ngrx website:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zUr--gYW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://howtomake.software/assets/blog/why-reducer-is-reducer/how-ngrx-works.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zUr--gYW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://howtomake.software/assets/blog/why-reducer-is-reducer/how-ngrx-works.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ngrx operates with 5 major concepts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;State&lt;/strong&gt; - represents the application state at the current moment.&lt;/p&gt;

&lt;p&gt;For instance, if we're building a todo list application our state will contain the list of tasks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;State&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Task&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;done&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;boolean&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;&lt;strong&gt;Action&lt;/strong&gt; - describes unique events that trigger state changes or side effects.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;addTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Add Task&lt;/span&gt;&lt;span class="dl"&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;removeTask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Remove Task&lt;/span&gt;&lt;span class="dl"&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;markTaskAsDone&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createAction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Mark Task As Done&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Selector&lt;/strong&gt; - describes how to select slice of the state to be consumed by the component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;getTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&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;getCompletedTasks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createSelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;task&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;done&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Reducer&lt;/strong&gt; - describe how your application's state will change based on actions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createReducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;addTask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// add task &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;&lt;strong&gt;Effect&lt;/strong&gt; - performs side effects, like interaction with the backend.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;saveTasks$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createEffect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;ofType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;saveTasks&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nx"&gt;mergeMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tasks&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// save tasks here&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;So, the main idea of the ngrx is that your application has a single source of truth - your state. It's an immutable object that can be changed only by the reducer. You can use parts of the state in your components selecting them using &lt;em&gt;selectors&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;If you need to change the state, you need to fire an action. Then, your reducer ought to intercept that action and publish a new version of the state (the state is immutable and can't be changed, that's&lt;br&gt;
why reducers don't change state, they just publish a new version of it).&lt;/p&gt;

&lt;p&gt;If you need to perform some side effect, like persisting data at the backend, you're using effects that intercepts an action, performs side effect and fires new action to change the state.&lt;/p&gt;

&lt;p&gt;With names of 4 concepts everything is clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;State&lt;/strong&gt; - application state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Action&lt;/strong&gt; - a command to change the state or perform side effect&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Selector&lt;/strong&gt; - selects part of the state&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Effect&lt;/strong&gt; - performs side effect&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But &lt;strong&gt;reducer&lt;/strong&gt;'s concept always was a dark horse for me.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why is it called a &lt;strong&gt;reducer&lt;/strong&gt;?&lt;/li&gt;
&lt;li&gt;Does it have any relation to the JavaScript's arrays reduce method?&lt;/li&gt;
&lt;li&gt;What was the intention to call it that way?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, I'll tell you answers to those questions! But before we dive into those sacred secrets, we ought to learn what is array reduce method 🚀&lt;/p&gt;
&lt;h2&gt;
  
  
  What is array reduce? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;So, what is the array reduce method? &lt;/p&gt;

&lt;p&gt;In fact, the reduce method accepts an initial state, then iterates over the array items and applies some transformations&lt;br&gt;
to the accumulator based on each item. It handles items one by one. Each iteration returns a new version of the accumulator&lt;br&gt;
that will be consumed by the next iteration. Here is the &lt;em&gt;gif&lt;/em&gt; that explains it step by step.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lr5iRSqt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://howtomake.software/assets/blog/why-reducer-is-reducer/how-reduce-works.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lr5iRSqt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_800/https://howtomake.software/assets/blog/why-reducer-is-reducer/how-reduce-works.gif" width="690" height="388"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Well, pretty easy, I'm right? I think it's a time to build a &lt;em&gt;reducer&lt;/em&gt; concept&lt;br&gt;
based on the &lt;em&gt;reduce&lt;/em&gt; method 🥳&lt;/p&gt;



&lt;h2&gt;
  
  
  Understanding reduce concept &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;In this section, I'm going to take an array reduce method and build a &lt;em&gt;reducer&lt;/em&gt; concept based on it.&lt;br&gt;
First of all, here we have an array and a &lt;em&gt;reduce&lt;/em&gt; call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;acc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;item&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;return&lt;/span&gt; &lt;span class="nx"&gt;acc&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It consumes an initial value - accumulator, that is &lt;strong&gt;0&lt;/strong&gt; and adds item to the accumulator at each iteration.&lt;br&gt;
The next step is to aply an appropriate naming to it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;action1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action5&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;initialStoreState&lt;/span&gt; &lt;span class="o"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// perform some transformation&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;initialStoreState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it looks like a &lt;strong&gt;reducer&lt;/strong&gt;! Am I right? We're close!&lt;br&gt;
Now, let's remember how we did state transformation at the reducer - using a switch/case statement!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;action1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action5&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;initialStoreState&lt;/span&gt; &lt;span class="o"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&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;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&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;case&lt;/span&gt; &lt;span class="na"&gt;Action1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// apply some transformations&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;Action2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// apply some transformations&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;Action3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// apply some transformations&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;Action4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// apply some transformations&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;Action5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// apply some transformations&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;initialStoreState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much better now, huh? Now, do you remember that ngrx operates with the immutable state objects? That&lt;br&gt;
mean we can't just apply some transformations to the state, we also need to create a new state object each&lt;br&gt;
time we do something at the reduce method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;action1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action5&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;initialStoreState&lt;/span&gt; &lt;span class="o"&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;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;reduce&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&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;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&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;case&lt;/span&gt; &lt;span class="na"&gt;Action1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// apply some transformations&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;newVersionOfTheState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;Action2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// apply some transformations&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;newVersionOfTheState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;Action3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// apply some transformations&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;newVersionOfTheState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;Action4&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// apply some transformations&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;newVersionOfTheState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="na"&gt;Action5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
      &lt;span class="c1"&gt;// apply some transformations&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;newVersionOfTheState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nx"&gt;initialStoreState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we're done! Looks like a common &lt;strong&gt;reducer&lt;/strong&gt; function, right? Or not? Something is still missing here...&lt;br&gt;
I mean, at the code above we're iterating over an array of items. While when we're dealing with ngrx actions, &lt;br&gt;
actions are not an array. It's a stream of events distributed over time.&lt;/p&gt;

&lt;p&gt;What concept can help us to handle a collection of events distributed over time? &lt;/p&gt;

&lt;p&gt;Of course, it's &lt;strong&gt;Observable&lt;/strong&gt;!&lt;/p&gt;

&lt;p&gt;Frankly speaking, &lt;strong&gt;Observable&lt;/strong&gt; is intended to be a stream of events. But for simplicity and a better understanding of&lt;br&gt;
my concept let's refer to it as just a collection of items distributed over time. Like an array, but distributed over time 😅.&lt;br&gt;
Hopefully, you already get my point here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// I can consume actions via subscribe&lt;/span&gt;
&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// handle action somehow&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// And can push new actions into the collection&lt;/span&gt;
&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;someAction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I have a plain definition of actions collection. I can push something into that collection, also, I can consume items from that collection.&lt;/p&gt;

&lt;p&gt;The next step is to create a state and to &lt;strong&gt;reduce&lt;/strong&gt; it somehow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// I can consume state via subscribe&lt;/span&gt;
&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// do something with it&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// And can push new version of the state&lt;/span&gt;
&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've created a state stream above. I'm using &lt;strong&gt;BehaviorSubject&lt;/strong&gt; here since it holds the last state inside and I can consume it whenever I want,&lt;br&gt;
even if subscribe on it after a new version of the state was pushed into the stream.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Listen for new actions&lt;/span&gt;
&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;

  &lt;span class="c1"&gt;// Get the latest version of the state&lt;/span&gt;
  &lt;span class="nx"&gt;withLatestFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

  &lt;span class="c1"&gt;// Perform actual reduce - create a new state version based on the latest state and an action&lt;/span&gt;
  &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&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;reducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;

  &lt;span class="c1"&gt;// Publish a new version of the state&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// It's an actual reducer function!&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&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;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Fire a new action&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;count&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;random&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;Above I have a very basic implementation of the ngrx store. Let's dissect it now!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;actions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Subject&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I have a stream of actions, and a stream of states.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Listen for new actions&lt;/span&gt;
&lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;

  &lt;span class="c1"&gt;// Get the latest version of the state&lt;/span&gt;
  &lt;span class="nx"&gt;withLatestFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;

  &lt;span class="c1"&gt;// Perform actual reduce - create a new state version based on the latest state and an action&lt;/span&gt;
  &lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(([&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;state&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;reducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;

  &lt;span class="c1"&gt;// Publish a new version of the state&lt;/span&gt;
&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newState&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, I'm listening for actions, getting the latest version of the state and applying a &lt;strong&gt;reducer&lt;/strong&gt; function to the latest state and a new action.&lt;br&gt;
This &lt;strong&gt;reducer&lt;/strong&gt; function returns a new version of the state (Did you notice that our &lt;strong&gt;reducer&lt;/strong&gt; function has exactly the same signature as it has &lt;br&gt;
in ngrx? I think we're going the right way!)&lt;/p&gt;

&lt;p&gt;After that, we're subscribing to the stream and publishing a new version of the state to the consumers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// It's an actual reducer function!&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;reducer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;action&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;count&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;count&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;Here is a &lt;strong&gt;reducer&lt;/strong&gt; function we built. It's a plain &lt;strong&gt;reducer&lt;/strong&gt; function as it exists in the ngrx.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Fire a new action&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;actions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;count&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;random&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;And finally, we have a click handler that fires new action.&lt;/p&gt;

&lt;p&gt;As you can see now, we went from the &lt;code&gt;array.reduce&lt;/code&gt; to the ngrx store step by step. We didn't built a &lt;em&gt;real&lt;/em&gt; ngrx store. We built a super simplified version&lt;br&gt;
that is intended to explain my mental model only. Hopefully, you get the idea 😅 &lt;/p&gt;

&lt;p&gt;Finally, I just want to formulate the idea.&lt;/p&gt;



&lt;h2&gt;
  
  
  So, why reducer is reducer? &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Reducer&lt;/strong&gt; is called &lt;strong&gt;reducer&lt;/strong&gt; since it &lt;em&gt;reduces&lt;/em&gt; a collection of events distributed over time and an application state. It does it the same way as &lt;strong&gt;array.reduce&lt;/strong&gt; function with only one difference - &lt;br&gt;
arrays are static, while collection of events are distributed over time.&lt;/p&gt;




&lt;p&gt;Stay tuned and &lt;a href="https://twitter.com/nikpoltoratsky"&gt;follow me on twitter!&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Originally published at &lt;a href="https://howtomake.software/blog/why-reducer-is-reducer"&gt;https://howtomake.software&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>ngrx</category>
      <category>rxjs</category>
    </item>
    <item>
      <title>Angular a11y: 11 tips on how to make your apps more accessible</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Thu, 20 Feb 2020 15:05:27 +0000</pubDate>
      <link>https://dev.to/nikpoltoratsky/angular-a11y-11-tips-on-how-to-make-your-apps-more-accessible-400h</link>
      <guid>https://dev.to/nikpoltoratsky/angular-a11y-11-tips-on-how-to-make-your-apps-more-accessible-400h</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This article, its updates, and more recent articles are hosted on the new platform inDepth.dev&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Nowadays approximately 15% of people have some kind of disability that doesn't allow them to use web applications in a common way - keyboard, mouse, touchscreen. That's where accessibility comes on to the stage.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Accessibility is the practice of making your websites usable by as many people as possible. We traditionally think of this as being about people with disabilities, but the practice of making sites accessible also benefits other groups such as those using mobile devices, or those with slow network connections. You might also think of accessibility as treating everyone the same, and giving them equal opportunities, no matter what their ability or circumstances. (source: &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/What_is_accessibility"&gt;developer.mozilla.org&lt;/a&gt;)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I prefer thinking about accessibility as about help for future me. While developing accessibility features, I'm always asking myself a question: "what may happen to me in the future?". What if I broke my arm or something else happen to me? Will I be able to use an application without a mouse? Without the keyboard? With the screen reader?&lt;/p&gt;

&lt;p&gt;Accessibility is not only for people with disabilities it's also about future you, about your old parents, who aren't able to interact with the web in a common way just because they're old.&lt;/p&gt;

&lt;p&gt;Also, there're different types of applications that require accessibility. I'm talking about government websites. For instance, the United States government has a resource that describes how to make your application accessible enough: &lt;a href="https://accessibility.digital.gov/"&gt;https://accessibility.digital.gov&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And my mission for today is to introduce the most basic principles on how to make your application accessible. In this article, you'll find 11 tips that will help you make your Angular application more accessible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note, that to use any of the techniques described below you should carefully go through the documentation. It’s easy to screw up accessibility when doing it without sufficient knowledge.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Use meaningful HTML&lt;/li&gt;
&lt;li&gt;Natural content flow&lt;/li&gt;
&lt;li&gt;Provide alternative content&lt;/li&gt;
&lt;li&gt;Think about contrast&lt;/li&gt;
&lt;li&gt;Don’t autofocus&lt;/li&gt;
&lt;li&gt;Don’t &lt;code&gt;outline: none&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Use ARIA attributes&lt;/li&gt;
&lt;li&gt;Use landmarks&lt;/li&gt;
&lt;li&gt;Provide a unique title for each page&lt;/li&gt;
&lt;li&gt;Use Angular CDK&lt;/li&gt;
&lt;li&gt;Test for a11y&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Use meaningful HTML
&lt;/h2&gt;

&lt;p&gt;The first and the simplest way to start with the accessibility is to start using plain old HTML for its purpose. I mean creating meaningful or semantic HTML. Since HTML elements are always used by assistive technologies for multiple purposes we ought to make sure that HTML is done right in our Angular applications. Let me explain why it is important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Built-in keyboard accessibility — native HTML elements always have built-in keyboard accessibility. Buttons are always focusable and clickable via keyboard, select elements are always navigable via keyboard and so on. If you’re building custom controls instead of using native HTML elements you’ll have to make them accessible by yourself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Good content structure with headings, paragraphs, lists, etc. — What’s the most important here is that content structure is used by the most screenreaders for navigation. For instance, most of the screenreaders build a kind of additional menu from headings on the page and allow their users to navigate to any heading at the page.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No table layouts — Tables were created with the purpose to display structured data. However, tons of pages nowadays are using tables for layouts. This approach may lead to inappropriate behavior and unstructured reads via screenreader. By the way, some of the modern screenreaders know the difference between data tables and layout tables, however, right now we can’t completely rely on them.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I’ve mentioned only a few points above, however, we have more reasons why to use semantic HTML. To find more information, you can start at &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML"&gt;developer.mozila.org&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Natural content flow
&lt;/h2&gt;

&lt;p&gt;HTML defines how elements are rendered and organized on a web page. It determines which element comes before another one, which one sits on top of another and so on. These rules that control the flow of content is called the HTML content flow.&lt;/p&gt;

&lt;p&gt;Looks like the content flow from left to right and from top to bottom is the most popular content flow across the web. However, in different cultures, you can notice different content flow like the right to left. And it’s very important to keep HTML content flow feel natural for the user. Especially important here to keep tab order at the page feels natural. However, user experience and natural tab order can be easily screwed up via improper usage of &lt;code&gt;flex boxes, floats, tabindex&lt;/code&gt; and other HTML features.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Reverse flex container — will mess tab order since elements positions will be different compared to the elements in the DOM.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Floats — CSS float introduces almost the same issue as reversed flex containers. It keeps the element at its place at the DOM but moves to another place on the screen.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;tabindex — tabindex is created to modify tab order, so it’s quite easy to introduce a mess using this HTML attribute. tabindex attr accepts integer values that define an order of elements in tab order of the page. Negative values remove an element from the tab order, 0 inserts elements in the natural tab order, positive values jump the element to the front of the natural tab order. If there are multiple elements with a tabindex greater than 0, the tab order starts from the lowest value that is greater than zero and works its way up. That’s why positive values for tabindex considered an anti-pattern. You can learn more about tabindex usage here: &lt;a href="https://developers.google.com/web/fundamentals/accessibility/focus/using-tabindex"&gt;https://developers.google.com/web/fundamentals/accessibility/focus/using-tabindex&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As we learned above, incorrect usage of HTML and CSS can introduce unexpected tab order on the page. Keyboard users will never expect the improper tab order and it’ll be hard for them to get how to navigate through the application.&lt;/p&gt;

&lt;p&gt;To learn more on natural tab order, please, check these articles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/keyboard-access/"&gt;Control focus with &lt;code&gt;tabindex&lt;/code&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://web.dev/control-focus-with-tabindex/"&gt;Keyboard access fundamentals&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Provide alternative content
&lt;/h2&gt;

&lt;p&gt;When you’re creating non text content on the web page, please, make sure you’ve provided a text alternative for your content. Let me elaborate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If your website contains images, charts, maps you ought to make sure this content has text alternatives for people who use screen readers. Since screen readers can’t read your images, charts, and maps you need to provide a text that contains all information from your infographics. For that purpose typically &lt;code&gt;alt=”Description”&lt;/code&gt; attribute is used on images.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Websites with video content ought to have subtitles. Easy as that, people who can’t use speakers ought to have the ability to understand your content. And here, subtitles come on to the stage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Empty &lt;code&gt;alt&lt;/code&gt; for decorative images &lt;code&gt;&amp;lt;img src=”…” alt=””&amp;gt;&lt;/code&gt;. While I mentioned that you ought to add alternative content for your graphical content, not each image has to be marked by the &lt;code&gt;alt&lt;/code&gt; attribute. If you mark your decorative images with the &lt;code&gt;alt&lt;/code&gt; attribute screenreader will try to announce them, however, it’s not what we want from decorative images.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Think about contrast
&lt;/h2&gt;

&lt;p&gt;You have to be always thinking about a content contrast since this part of a11y affects almost all users of your application. If the content on the web page has low contrast with the background it’s really hard to read it even without any sight disabilities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RmgicOcP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/bLy7Pv2/image.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RmgicOcP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://i.ibb.co/bLy7Pv2/image.png" alt="Chrome color picker with conformance level errors" width="363" height="485"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’re using google chrome, you can check a contrast of your content at the styles tab.&lt;/p&gt;

&lt;p&gt;So, just select an HTML element, open its CSS properties and click at any color style. You may notice a new section at the bottom of the color picker that notifies you about the contrast ratio between element text and background.&lt;/p&gt;

&lt;p&gt;At the image above, I have an issue with the contrast. Also, here you can notice two additional lines on the color palette and red signs along with A letters at the bottom. Those red signs with A letters indicate &lt;a href="https://www.ucop.edu/electronic-accessibility/standards-and-best-practices/levels-of-conformance-a-aa-aaa.html"&gt;WCAG Conformance levels&lt;/a&gt; — a metric that indicates how accessible your website is. For the current situation with the contrast it means the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;If your color above the top line (&lt;strong&gt;A&lt;/strong&gt; Conformance level) — you have a minimum level of accessibility and does not achieve broad accessibility for many situations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If your color between lines (&lt;strong&gt;AA&lt;/strong&gt; Conformance level) — it’s ok. WCAG recommends you have at least &lt;strong&gt;AA&lt;/strong&gt; Conformance level for your websites.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If your color below the bottom line (&lt;strong&gt;AAA&lt;/strong&gt; Conformance level) — you’re great. However, &lt;strong&gt;AAA&lt;/strong&gt; (the highest) level of accessibility can’t be achieved for all accessibility criteria.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Don’t autofocus
&lt;/h2&gt;

&lt;p&gt;Autofocus is hard to get for screenreader users. Autofocus can dump screenreader users into your form with zero context, leaving them lost and confused on your page.&lt;/p&gt;

&lt;p&gt;Autofocus can also confuse regular users, especially on mobile. So keep it simple, let people click into your inputs when they are ready. To learn more about autofocus issue please, refer to &lt;a href="https://www.brucelawson.co.uk/2009/the-accessibility-of-html-5-autofocus/"&gt;this article&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t &lt;code&gt;outline: none&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;It’s a pretty common approach to add outline: none style into global application’s styles since the default browser outline is ugly and can ruin your design. However, an outline is a must for keyboard users who aren’t using the mouse for interaction with your application. The outline allows them to see what section on the page is selected right now and helps them to navigate across your application.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;So, the best approach is to keep an outline and just style it to fit application design. This is amazing since the outline is a common behavior for each website and will be easily recognized by the user.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Another way is to style focused elements another way: background, border or whatever. When using this approach, avoid using color alone as the only visual means of determining focus, as colorblind people may not be able to distinguish the focus state from the inactive state.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Also, if you finally decided to remove the outline in your application, you can control its behavior through JavaScript. Detect mouse users and hide outline for them, then, detect keyboard activity and show outline for them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally, there is a native approach for hiding/removing outline for the user — The &lt;code&gt;:focus-visible&lt;/code&gt; pseudo-class applies while an element matches the &lt;code&gt;:focus&lt;/code&gt; pseudo-class and the user-agent determines via heuristics that the focus should be made evident on the element. You can read about it deeper here: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible"&gt;https://developer.mozilla.org/en-US/docs/Web/CSS/:focus-visible&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information, I would suggest you refer to &lt;a href="https://a11yproject.com/posts/never-remove-css-outlines/"&gt;this article from a11yproject&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use ARIA attributes
&lt;/h2&gt;

&lt;p&gt;ARIA is shorthand for &lt;a href="https://www.w3.org/WAI/standards-guidelines/aria/"&gt;Accessible Rich Internet Applications&lt;/a&gt;. ARIA is a set of attributes you can add to HTML elements that define ways to make web content and applications accessible to users who use assistive technologies. When accessibility issues cannot be managed with native HTML, ARIA can help bridge those gaps.&lt;/p&gt;

&lt;p&gt;There are three main components used in ARIA: Roles, States, and Properties:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Role — defines a type of user interface element. (button, menuitem, scrollbar)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;States and properties— defines a state of an element (aria-checked, aria-labelledby, aria-activedescendant).&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But remember the rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Use native HTML at all times, unless it’s absolutely, positively impossible to make an element accessible otherwise.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you think something can’t be done using HTML, please, check it at &lt;a href="https://www.html5accessibility.com/"&gt;HTML Accessibility site&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use landmarks
&lt;/h2&gt;

&lt;p&gt;This section is related to semantic HTML since HTML 5 introduced a number of semantic attributes that help screen reader users to perform navigation across the page. For instance, a screen reader will announce the start and end of each landmark on a page, and its web rotor will display a list of these roles/regions.&lt;/p&gt;

&lt;p&gt;You can think about landmarks as about a set of anchors assistive technologies may navigate to. So, users may skip some sections or just go directly to a specific section of your web page.&lt;/p&gt;

&lt;p&gt;Here is the list of the most common landmark: &lt;code&gt;article, aside, nave, main, footer, header&lt;/code&gt;, etc.&lt;/p&gt;

&lt;p&gt;However, in some specific situations (for instance, old browsers support), you need to change the behavior of the screen reader and here ARIA landmark attributes becomes handy. Landmark attributes are HTML attributes assigned to specific sections of your website. These attributes allow you to change the meaning of the specific landmark for the screen readers.&lt;/p&gt;

&lt;p&gt;You can learn more about HTML and ARIA landmarks here: &lt;a href="https://www.w3.org/TR/wai-aria-practices/examples/landmarks/HTML5.html"&gt;https://www.w3.org/TR/wai-aria-practices/examples/landmarks/HTML5.html&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Provide a unique title for each page
&lt;/h2&gt;

&lt;p&gt;A unique title for each page is a must for screenreader users since it’s the first thing that is announced by the screenreader. I bet it’s a quite big issue for Angular applications since Angular applications are single-page applications. And have one common title for each page by default.&lt;/p&gt;

&lt;p&gt;However, it can be fixed using &lt;code&gt;Title&lt;/code&gt; service provided by the Angular. It allows you to set a page title through the simple API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Title) {&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setTitle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Cool Page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Use Angular CDK
&lt;/h2&gt;

&lt;p&gt;Since we’re talking about accessibility for Angular applications it’s must mention &lt;a href="https://material.angular.io/cdk/a11y"&gt;Angular CDK a11y&lt;/a&gt; package that allows you speed up accessibility development via providing implementations for common patterns. Let’s peek a boo on functionalities provided:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;ListKeyManager — allows you to create keyboard navigable lists seamlessly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Focus trap — traps a focus inside an element. Widely used for modal dialogs to trap a focus inside and not allow the user to tab out of the modal dialog.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Live announcer — provides the easiest way to announce something for screenreader users. It’s especially important for applications that have notifications and users with screenreaders. Since screenreaders can’t tell the user about notification by default.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Focus monitor — allows monitoring focus on an element and its descendants. It’s like listening for &lt;code&gt;focus&lt;/code&gt; and &lt;code&gt;blur&lt;/code&gt; events on the element, but packed into one service with the simple API and also allows you to understand &lt;em&gt;how&lt;/em&gt; that element was focused — mouse, keyboard, touch or programmatically.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Styling utilities — a few SCSS utilities invented to help you building accessible components. It includes functionalities like the ability to hide elements from the screen while keeping them available for screen readers and helping you to target high contrast color schemes in your users.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Test for accessibility
&lt;/h2&gt;

&lt;p&gt;If you decided to build an accessible application you ought to think about testing for accessibility. It’ll allow you not to miss something important while developing an app. Also, it’ll help you to deal with the regression.&lt;br&gt;
There are two ways for testing a website for accessibility:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Manual testing — manual testing is often required since we can’t get all the issues using automated testing. Here is an amazing article on how to start manual accessibility reviews: &lt;a href="https://developers.google.com/web/fundamentals/accessibility/how-to-review"&gt;https://developers.google.com/web/fundamentals/accessibility/how-to-review&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Automated testing — in spite of we can’t get all the accessibility issues using automated testing we can save tons of time using it. So, please, check &lt;a href="https://medium.com/angular-in-depth/test-for-accessibility-and-help-millions-of-people-97d86f72e2c4"&gt;Tim Deschryver article&lt;/a&gt; on accessibility testing tools overview.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




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

&lt;p&gt;Hopefully, you already get that accessibility is a must for almost any type of web application. It improves user experience and removes barriers for almost any users and allows them to use web applications in a seamless way.&lt;/p&gt;

&lt;p&gt;In this article, I’ve mentioned the most basic and important things you need to do to start with accessibility. Let’s make the web more accessible together!&lt;/p&gt;

&lt;p&gt;Thank you for reading!&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful resource:
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Amazing Introductions for Accessibility:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Web Accessibility Initiative — &lt;a href="https://www.w3.org/WAI/"&gt;https://www.w3.org/WAI/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The US Government guide on accessibility — &lt;a href="https://accessibility.digital.gov/"&gt;https://accessibility.digital.gov/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Developer Mozilla Network — &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Accessibility"&gt;https://developer.mozilla.org/en-US/docs/Web/Accessibility&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Guides and researches
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://webaim.org/"&gt;https://webaim.org/&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How to build accessible components
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/WAI/tutorials/page-structure/"&gt;https://www.w3.org/WAI/tutorials/page-structure/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://inclusive-components.design/"&gt;https://inclusive-components.design/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.w3.org/TR/wai-aria-practices-1.1/"&gt;https://www.w3.org/TR/wai-aria-practices-1.1/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.smashingmagazine.com/printed-books/inclusive-components/"&gt;https://www.smashingmagazine.com/printed-books/inclusive-components/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;A11yCast by Rob Dodson — &lt;a href="https://www.youtube.com/playlist?list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g"&gt;https://www.youtube.com/playlist?list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>angular</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Nebular Hacktoberfest</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Thu, 03 Oct 2019 08:55:43 +0000</pubDate>
      <link>https://dev.to/nikpoltoratsky/nebular-hacktoberfest-1gca</link>
      <guid>https://dev.to/nikpoltoratsky/nebular-hacktoberfest-1gca</guid>
      <description>&lt;p&gt;Hacktoberfest is started a few days ago! And you still have no idea on how to start your​ amazing journey into the open-source world and finally get your T-Shirt? I have an answer for you. One of the best ways to start open-source contributions is to help us with &lt;a href="https://github.com/akveo/nebular"&gt;Nebular&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is Nebular?
&lt;/h2&gt;

&lt;p&gt;Nebular is a customizable Angular 8 UI Library with a focus on beautiful design and the ability to adapt it to your brand easily. It comes with 4 stunning visual themes, a powerful theming engine with runtime theme switching and support of custom CSS properties mode. Nebular is based on Eva Design System specifications.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to start contributions?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Open issues at the &lt;a href="https://github.com/akveo/nebular"&gt;GitHub repository&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Search for issues for starters (issues which contain following labels on GitHub):

&lt;ul&gt;
&lt;li&gt;help wanted&lt;/li&gt;
&lt;li&gt;good first issue&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Deal with those issues!&lt;/li&gt;
&lt;li&gt;Get your T-Shirt!&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;What's more important here, don't hesitate! Find interesting issues, deal with them and have fun! 🥳&lt;br&gt;
Drop me a line if you have any questions - &lt;a href="http://twitter.com/nikpoltoratsky"&gt;@nikpoltoratsky&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Debugging - you’re doing it wrong. 10 techniques to find a bug in your code</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Tue, 23 Jul 2019 13:02:53 +0000</pubDate>
      <link>https://dev.to/nikpoltoratsky/debugging-you-re-doing-it-wrong-10-techniques-to-find-a-bug-in-your-code-4f41</link>
      <guid>https://dev.to/nikpoltoratsky/debugging-you-re-doing-it-wrong-10-techniques-to-find-a-bug-in-your-code-4f41</guid>
      <description>&lt;p&gt;Do you remember those long, long hours spent on debugging? When you're staring at a codebase and can't figure out what exactly went wrong? You're not alone! I think all developers struggle with debugging from time to time. That's why in the article I'm going to tell you about my favorite approaches to finding bugs in the code.&lt;/p&gt;

&lt;h2&gt;
  
  
  Table of contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Google error message&lt;/li&gt;
&lt;li&gt;Console log everything&lt;/li&gt;
&lt;li&gt;Use debugger&lt;/li&gt;
&lt;li&gt;Problem localization&lt;/li&gt;
&lt;li&gt;Create a few tests&lt;/li&gt;
&lt;li&gt;Analyze logs&lt;/li&gt;
&lt;li&gt;Ask a friend&lt;/li&gt;
&lt;li&gt;Git bisect&lt;/li&gt;
&lt;li&gt;Talk to a rubber duck&lt;/li&gt;
&lt;li&gt;Tambourine Dancing&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Google error message
&lt;/h2&gt;

&lt;p&gt;I'm not going to sort those tips by usefulness but &lt;strong&gt;google error message&lt;/strong&gt; is at the first place by a reason. I think, if you can't even understand an error message from the first sight, the easiest way to solve the problem is to &lt;strong&gt;google error message&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In most of the cases, the error message you are facing was googled before by someone else. We have a lot of beautiful places like &lt;em&gt;StackOverflow&lt;/em&gt; and &lt;em&gt;GitHub&lt;/em&gt; issues, where people aim to help each other. That's why you can not only find the answer but also steps to avoid such error or motivation why this error occurred in the first place.  So, why not to google the error? It's the easiest way here.&lt;/p&gt;




&lt;h2&gt;
  
  
  Console log everything
&lt;/h2&gt;

&lt;p&gt;I think it's one of the most popular ways to find a bug in the codebase - add a tenth of &lt;code&gt;console.log(...)&lt;/code&gt; statements across the codebase, rerun the application and try to figure out what went wrong.&lt;/p&gt;

&lt;p&gt;I like it, and from my point of view, it's the right solution for simple issues, which are already localized to a few classes. But it's always a bad idea to start seeking with &lt;code&gt;console.log(...)&lt;/code&gt;s when you have no idea what's going on here and where that creepy bug resides. Because in that case you may miss something important not logged and you'll have to add console logs and rerun application multiple times until you find the cause of failure.&lt;/p&gt;




&lt;h2&gt;
  
  
  Use debugger
&lt;/h2&gt;

&lt;p&gt;I don't think I have too much to say here. All developers know what debugger is and why to use it. Instead, I'm going to tell you about a small discussion that flared up the other day in the office with one of my teammates.&lt;/p&gt;

&lt;p&gt;A few days ago, I was discussing different ways of debugging with one of my teammates (that's the reason why this article appeared). And I said that one of the most robust ways to find an issue is to use a debugger. Easy as that - you're setting breakpoints, then, performing some actions and going step by step through your codebase, observing how the state of the application changes. What can be more straightforward as that?&lt;/p&gt;

&lt;p&gt;While my teammate introduced an exciting idea - when you're using the debugger, you are not training your analytical skills and critical thinking. The reason is that with debugger you're just staring at the window with variables and waiting for incorrect behavior. While when you're digging through the codebase without the debugger, you're more focused and trying to understand what's going on and learn something new each time you're seeking for a bug.&lt;/p&gt;

&lt;p&gt;What do you think about debugger vs. manual investigations? Please, give me your ideas in the comments.&lt;/p&gt;




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

&lt;p&gt;The key idea of the &lt;strong&gt;Problem localization&lt;/strong&gt; method is to comment/remove a code step by step until you figure out what went wrong. It works especially useful in cases when you are writing an algorithm or some business logic a pretty long time without compiling and executing the application.&lt;/p&gt;

&lt;p&gt;In such cases, I'm always doing something wrong, and the easiest way for me is to comment code partially and try to intercept disappeared errors. Then, repeat it until all bugs will be found and revamped.&lt;/p&gt;

&lt;p&gt;In some cases it might be a good idea to use the binary search line approach when you comment half of the code (or remove half of the files) - then check if the error is still here. If yes repeat the same with the half of this half, if now - same with the other half.&lt;/p&gt;

&lt;p&gt;Of course, this only works in particular cases when you are able to comment/ remove code parts still keeping it working.&lt;/p&gt;




&lt;h2&gt;
  
  
  Create a few tests
&lt;/h2&gt;

&lt;p&gt;Ok, that's the crazy one, whereas it could be useful in some particular cases. From my sight, it works well when you have some algorithm that works incorrectly, and is too complex to write &lt;code&gt;console.log&lt;/code&gt;'s or go through it using the debugger.&lt;/p&gt;

&lt;p&gt;In that case, it might be useful to write a few tests for it. Tests could help you localize the issue in the algorithm.&lt;/p&gt;

&lt;p&gt;After that, when the bug is localized, and you know where to search, you may use another approach to fix it finally.&lt;/p&gt;




&lt;h2&gt;
  
  
  Analyze logs
&lt;/h2&gt;

&lt;p&gt;Yep, I know you hate to analyze all those 10mb text files with logs. But quite often it could save you a few hours of debugging. Of course, logging has to be configured adequately first of all. Collected log files have to be kept during the appropriate amount of time. But if all conditions are met - you're lucky. It's like console logging, but you already have all &lt;code&gt;console.log&lt;/code&gt;s on their places and can just read through actions performed on your system.&lt;/p&gt;

&lt;p&gt;But unfortunately, quite often it's a dream... We're not always paying enough attention to logging.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ask a friend
&lt;/h2&gt;

&lt;p&gt;It's pretty obvious, but we're not doing it quite often. I think all of us have more experienced teammates at the office. Otherwise, we can find an expert across the internet. Don't be afraid, ok? People are always ready to help you!&lt;/p&gt;

&lt;p&gt;But. You need to satisfy one requirement - check all the available sources of the information before asking somebody. If you're asking for help with something easy, which is written on the second page of the documentation, then. Well. Be ready to run away!&lt;/p&gt;




&lt;h2&gt;
  
  
  Git bisect
&lt;/h2&gt;

&lt;p&gt;Git not only helps us to keep an application revisions history, but it also provides us with a few tools for debugging. One of those tools is a &lt;strong&gt;git bisect&lt;/strong&gt; - tool for performing a binary search across your git history. It's quite useful in case you didn't work with the codebase for a while, and since your last intervention, a few hundred commits were added. And now, you encounter a bug and have no idea how and when it appeared. But you remember you didn’t have it in version &lt;code&gt;2.0.15&lt;/code&gt;, for instance.&lt;/p&gt;

&lt;p&gt;In that case &lt;strong&gt;git bisect&lt;/strong&gt; will help you. The idea is pretty simple, you start the debugging process with &lt;code&gt;git bisect start&lt;/code&gt;, then, we need to mark the current version as &lt;em&gt;bad&lt;/em&gt; version because we have a bug here - &lt;code&gt;git bisect bad&lt;/code&gt;. After that, we have to tell git about a &lt;em&gt;good&lt;/em&gt; working version: &lt;code&gt;git bisect good 2.0.15&lt;/code&gt;. On that stage, setup is done, and we can start searching.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;git bisect&lt;/strong&gt; selects commit in the middle of &lt;em&gt;bad-good&lt;/em&gt; range and checks out on it. Then, we have to check if we have that bug in this revision? If yes - run &lt;code&gt;git bisect bad&lt;/code&gt;, if no - run &lt;code&gt;git bisect good&lt;/code&gt;. Then, git will choose a new commit in the original &lt;em&gt;bad-good&lt;/em&gt; range, and we have to repeat the process until a commit with the bug is found.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;git bisect&lt;/strong&gt; is a pretty powerful tool that's why a full description will be out of the format of the article, but &lt;a href="https://git-scm.com/docs/git-bisect" rel="noopener noreferrer"&gt;here is a link with a good explanaition&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Talk to a rubber duck
&lt;/h2&gt;

&lt;p&gt;It's one of the most potent methods of understanding what's going on in the code. The main idea is that you need to find a rubber duck, put it in front of yourself and then, explain your system to it, starting from general concepts and then going line by line. &lt;a href="https://rubberduckdebugging.com" rel="noopener noreferrer"&gt;You can read more about it here&lt;/a&gt;. I like this idea and use it regularly, so, let me tell you a short story about how I used it the first time and even didn't notice it.&lt;/p&gt;

&lt;p&gt;When I just started my career as the programmer, I was building an Android application which contained quite complex handwritten animations. I made one of those animations carefully, step by step, and everything was fine until I stuck.&lt;/p&gt;

&lt;p&gt;I had an animation code for no more than 150 lines. And I couldn't find a problem why it wasn't working. I checked all the algorithms multiple times but still nothing. After staring at the screen for a few hours, I decided to ask a teammate for help.&lt;/p&gt;

&lt;p&gt;I've started a detailed explanation of how that animation works, and in a minute, I found the issue! One of the methods implicitly converted &lt;code&gt;float&lt;/code&gt; to &lt;code&gt;int&lt;/code&gt;🤦‍♂️🤦‍♂️🤦‍♂️🤦‍♂️🤦‍♂️. And It took me one minute to understand it when I tried to explain it in detail to my teammate.&lt;/p&gt;

&lt;p&gt;That time I even didn't know that's it's a method of a rubber duck. I realized that, later. But I already understood how powerful it is.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tambourine Dancing
&lt;/h2&gt;

&lt;p&gt;It's my favorite way to solve problems with the software. All you need is tambourine. You need to dance around your workstation, knocking on a tambourine. It will be a big plus if you have a tambourine with the logo of technology you're working with. For instance, I have a tambourine which helps me to solve issues with my microservices:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flosvpavixfjxvq26r5ud.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flosvpavixfjxvq26r5ud.jpg" alt="Java Tambourine"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;But it's utterly useless for front-end applications.&lt;/p&gt;




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

&lt;p&gt;Thank you for reading this! Hopefully, you've learned something new from the article. The last thing I want to reveal here for those of you who read the material to the end is that the most powerful way to deal with bugs and issues in the codebase is to write code without bugs. Just, ask your manager. 😅&lt;/p&gt;

&lt;p&gt;Anyway, be focused and consistent. Do your investigation step by step and use the techniques mentioned above. And you'll resolve all your bugs efficiently.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/nikpoltoratsky" rel="noopener noreferrer"&gt;Follow me on Twitter to staying tuned&lt;/a&gt; and let me know if you have any particular topics you would like to hear about!&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>challenge</category>
      <category>explainlikeimfive</category>
    </item>
    <item>
      <title>Don't follow RxJS Best Practices</title>
      <dc:creator>Nik Poltoratsky</dc:creator>
      <pubDate>Mon, 15 Jul 2019 09:50:13 +0000</pubDate>
      <link>https://dev.to/nikpoltoratsky/don-t-follow-rxjs-best-practices-4893</link>
      <guid>https://dev.to/nikpoltoratsky/don-t-follow-rxjs-best-practices-4893</guid>
      <description>&lt;p&gt;Nowadays more and more developers learn RxJS and use it properly with best practices in mind. But we shouldn't. All those so-called best practices require to learn something new and to add additional code in your projects.&lt;br&gt;
Moreover, using the best practices we're risking to create a good code base and make your teammates happy! 🌈&lt;br&gt;
Stop being a gray mass! Break the rules! Stop using best practices!&lt;/p&gt;

&lt;p&gt;Here are my suggestions to you on how to deal with those so-called RxJS best practices in Angular:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Don't unsubscribe&lt;/li&gt;
&lt;li&gt;Subscribe inside subscribe inside subscribe inside…&lt;/li&gt;
&lt;li&gt;Never use pure functions&lt;/li&gt;
&lt;li&gt;Always subscribe manually, don't use async pipe&lt;/li&gt;
&lt;li&gt;Expose subjects from your services&lt;/li&gt;
&lt;li&gt;Always pass streams to child components&lt;/li&gt;
&lt;li&gt;Marble diagrams? No, it's not for you&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Don't unsubscribe &lt;a&gt;&lt;/a&gt;
&lt;/h1&gt;

&lt;p&gt;Everybody says that we have to always unsubscribe from observables to prevent memory leaks.&lt;/p&gt;

&lt;p&gt;But I can't agree with it. Seriously, who decided that you have to unsubscribe from observables? You don't have to do that. Let's play a game! Which unsubscribe implementation of those Angular components is the best?&lt;/p&gt;

&lt;p&gt;That one with &lt;code&gt;takeUntil&lt;/code&gt; operator?&lt;/p&gt;

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

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;destroyed$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Subject&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;myInfiniteStream$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;takeUntil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroyed$&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroyed$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroyed$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;complete&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Or that one with &lt;code&gt;takeWhile&lt;/code&gt; operator?&lt;/p&gt;

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

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;alive&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="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;myInfiniteStream$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;takeWhile&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alive&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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="p"&gt;}&lt;/span&gt;
  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alive&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Exactly! Neither! Both &lt;code&gt;takeWhile&lt;/code&gt; and &lt;code&gt;takeUntil&lt;/code&gt; operators are implicit and may be hard to read 🤓 (sarcasm). The best solution is to store each subscription in a separate variable and then unsubscribe on component destroy in an explicit way:&lt;/p&gt;

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

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myInfiniteStream$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;That works especially good in cases when you have multiple subscriptions:&lt;/p&gt;

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

&lt;span class="nc"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;OnDestroy&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;subscription5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myInfiniteStream1$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myInfiniteStream2$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myInfiniteStream3$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myInfiniteStream4$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription5&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myInfiniteStream5$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnDestroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription4&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscription5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;But that solution is not perfect yet. What could be done better? How do you feel? How could we make that code more clean and readable?&lt;br&gt;
Yeah, I have the answer for you! Let's remove all that ugly unsubscribe statements at all.&lt;/p&gt;

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

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;myInfiniteStream$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&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="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;Excellent! We've removed all the redundant code and now it looks simpler and even saves us a bit of memory on our hard drives. But what will happen with &lt;code&gt;myInfiniteStream$&lt;/code&gt; subscription?&lt;/p&gt;

&lt;p&gt;Forget about it! 😅 Let's leave that job for the garbage collector, otherwise, why does it exist, right?&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Use subscribe inside subscribe inside subscribe inside…
&lt;/h1&gt;

&lt;p&gt;Everybody says that we should use &lt;code&gt;*Map&lt;/code&gt; operators to chain observables instead of subscribing inside subscribes to prevent callback hell.&lt;/p&gt;

&lt;p&gt;But I can't agree with it. Seriously, why not? Why should we use all those &lt;code&gt;switchMap&lt;/code&gt;/&lt;code&gt;mergeMap&lt;/code&gt; operators? How do you feel about that code? Easy to read? Do you really like your teammates so much?&lt;/p&gt;

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

&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;getComments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&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;Don't you think it too neat and cute? You shouldn't write code that way! You have another choice, take a look here:&lt;/p&gt;

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

&lt;span class="nf"&gt;getUser&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nf"&gt;getDetails&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;getPosts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;details&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;getComments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;posts&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;comments&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  

        &lt;span class="c1"&gt;// handle all the data here&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Much better, huh?! Always write code this way if you hate your teammates and don't want to learn new RxJS operators.&lt;/p&gt;

&lt;p&gt;Be bright! Let your team members feel a bit of nostalgia with callback hell.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Never use pure functions
&lt;/h1&gt;

&lt;p&gt;Everybody says that we should use pure functions to make our code predictable and easier to test.&lt;/p&gt;

&lt;p&gt;But I can't agree with it. Seriously, why should you use pure functions? Testability? Composability? It's hard, it would be much easier to affect the global world. Let's take a look at the example:&lt;/p&gt;

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

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateTax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;productPrice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productPrice&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tax&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="nx"&gt;productPrice&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 instance, we have a function which calculates a tax - it's a pure function it will always return the same result for the same parameters. It's easy to test and compose with other functions. But, do we really need that behavior? I don't think so. It would be easier to use a function without parameters:&lt;/p&gt;

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

&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;productPrice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;calculateTax&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;productPrice&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tax&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="nx"&gt;productPrice&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;Indeed, what can go wrong? 😉&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Always subscribe manually, don't use async
&lt;/h1&gt;

&lt;p&gt;Everybody says that we have to use &lt;code&gt;async&lt;/code&gt; pipe in Angular templates to facilitate subscriptions management in components.&lt;/p&gt;

&lt;p&gt;But I can't agree with it. We've already discussed subscriptions management with &lt;code&gt;takeUntil&lt;/code&gt; and &lt;code&gt;takeWhile&lt;/code&gt; and agreed that these operators are from an evil one. Though, why should we treat &lt;code&gt;async&lt;/code&gt; pipe another way?&lt;/p&gt;

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

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;  
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;span&amp;gt;{{ data$ | async }}&amp;lt;/span&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;myInfiniteStream$&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Do you see that? Clean, readable, easy to maintain code! Argh. It's not allowed. As for me, it would be much better to put the data in local variable and just use that variable in the template.&lt;/p&gt;

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

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;  
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;span&amp;gt;{{ data }}&amp;lt;/span&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nx"&gt;myInfiniteStream$&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;




&lt;h1&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Expose subjects from your services
&lt;/h1&gt;

&lt;p&gt;There is a pretty common practice to use Observable Data Services in Angular:&lt;/p&gt;

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

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asObservable&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nf"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;foo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nf"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Here we're exposing data stream as observable. Just to make sure it can be changed only through a data service interface. But it confuses people.&lt;/p&gt;

&lt;p&gt;You want to change the data - you have to change the data.&lt;/p&gt;

&lt;p&gt;Why add additional methods if we can change the data on the place? Let's rewrite the service to make it easier to use;&lt;/p&gt;

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

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;providedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DataService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;BehaviorSubject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BehaviorSubject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;bar&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Yeah! Do you see that? Our data service became smaller and easier to read! Also, now we can put almost anything in our data stream! Awesome, don't you think so?🔥&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Always pass streams to child components
&lt;/h1&gt;

&lt;p&gt;Have you ever heard about Smart/Dump components pattern, that can help us to decouple components from each other? Also, that pattern prevents child component from triggering actions in parent components:&lt;/p&gt;

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

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-parent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;app-child [data]="data$ | async"&amp;gt;&amp;lt;/app-child&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ParentComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-child&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChildComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Data&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;Do you like it? Your teammates also like it. In case you want to revenge them, you need to rewrite your code in the following way:&lt;/p&gt;

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

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-parent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;app-child [data$]="data$"&amp;gt;&amp;lt;/app-child&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ParentComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="nx"&gt;data$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;http&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(...);&lt;/span&gt;
  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-child&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ChildComponent&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnInit&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nl"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nf"&gt;ngOnInit&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="c1"&gt;// Trigger data fetch only here&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Do you see that? We're not handling subscriptions in the parent component anymore. We're just passing subscription to the child component.&lt;br&gt;
If you follow that practice your team members will cry tears of blood during debugging, believe me.&lt;/p&gt;




&lt;h1&gt;
  
  
  &lt;a&gt;&lt;/a&gt; Marble diagrams? No, it's not for you
&lt;/h1&gt;

&lt;p&gt;Do you know what are marble diagrams? No? It's good for you!&lt;/p&gt;

&lt;p&gt;Let's assume we wrote the following function and going to test it:&lt;/p&gt;

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

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;numTwoTimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;obs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&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;obs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&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;x&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Many of us will use marble diagrams to test the function:&lt;/p&gt;

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

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;multiplies each number by 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="nf"&gt;createScheduler&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(({&lt;/span&gt; &lt;span class="nx"&gt;cold&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expectObservable&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;values&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;a&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;b&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;x&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;y&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;z&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&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;numbers$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;cold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a-b-c-|&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;number&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;resultDiagram&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-y-z-|&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;expectObservable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;numTwoTimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers$&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nf"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resultDiagram&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;But, who the hell wants to learn a new concept of marble diagrams? Who wants to write clean and laconic code? Let's rewrite the test in a common manner.&lt;/p&gt;

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

&lt;span class="nf"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;multiplies each number by 2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;done&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;numbers$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;interval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nf"&gt;take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;// This emits: -1-2-3-|&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;numbersTwoTimes$&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;numTwoTimes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;numbers$&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;results&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;

  &lt;span class="nx"&gt;numbersTwoTimes$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nf"&gt;done&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="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="nf"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toEqual&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;])&lt;/span&gt;
      &lt;span class="nf"&gt;done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


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

&lt;/div&gt;

&lt;p&gt;Yeah! It looks one hundred times better now!&lt;/p&gt;




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

&lt;p&gt;You're a hero if you've read all the advice above. But. Well. If you recognized your train of thoughts, I have a piece of bad news for you. It was a joke.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fopyhji5jq8yh2jf3pmfd.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%2Fopyhji5jq8yh2jf3pmfd.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Please, never do what I said in that article. Never let your teammates cry and hate you. Always strive to be a decent and neat person. Save the world - use patterns and best practices!&lt;/p&gt;

&lt;p&gt;I just decided to cheer you up and make your day a little bit better. Hopefully, you like it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/NikPoltoratsky" rel="noopener noreferrer"&gt;Stay tuned&lt;/a&gt; and let me know if you have any particular Angular topics you would like to hear about!&lt;/p&gt;

</description>
      <category>angular</category>
      <category>rxjs</category>
      <category>typescript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
