<?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: Baruch Odem</title>
    <description>The latest articles on DEV Community by Baruch Odem (@baruchiro).</description>
    <link>https://dev.to/baruchiro</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%2F156174%2F83c41e13-56fd-456f-8c8c-b7c45adfc2ca.jpeg</url>
      <title>DEV Community: Baruch Odem</title>
      <link>https://dev.to/baruchiro</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/baruchiro"/>
    <language>en</language>
    <item>
      <title>ElasticSearch get the first time that item is shown</title>
      <dc:creator>Baruch Odem</dc:creator>
      <pubDate>Wed, 04 Aug 2021 12:41:02 +0000</pubDate>
      <link>https://dev.to/baruchiro/elasticsearch-get-the-first-time-that-item-is-shown-2j6i</link>
      <guid>https://dev.to/baruchiro/elasticsearch-get-the-first-time-that-item-is-shown-2j6i</guid>
      <description>&lt;div class="ltag__stackexchange--container"&gt;
  &lt;div class="ltag__stackexchange--title-container"&gt;
    
      &lt;div class="ltag__stackexchange--title"&gt;
        &lt;h1&gt;
          &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7Gn-iPj_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/stackoverflow-logo-b42691ae545e4810b105ee957979a853a696085e67e43ee14c5699cf3e890fb4.svg" alt=""&gt;
            &lt;a href="https://stackoverflow.com/questions/68649757/elasticsearch-get-the-first-time-that-item-is-shown" rel="noopener noreferrer"&gt;
               ElasticSearch get the first time that item is shown
            &lt;/a&gt;
        &lt;/h1&gt;
        &lt;div class="ltag__stackexchange--post-metadata"&gt;
          &lt;span&gt;Aug  4 '21&lt;/span&gt;
            &lt;span&gt;Comments: 8&lt;/span&gt;
            &lt;span&gt;Answers: 0&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;a class="ltag__stackexchange--score-container" href="https://stackoverflow.com/questions/68649757/elasticsearch-get-the-first-time-that-item-is-shown" rel="noopener noreferrer"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y9mJpuJP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/stackexchange-arrow-up-eff2e2849e67d156181d258e38802c0b57fa011f74164a7f97675ca3b6ab756b.svg" alt=""&gt;
        &lt;div class="ltag__stackexchange--score-number"&gt;
          0
        &lt;/div&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wif5Zq3z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/stackexchange-arrow-down-4349fac0dd932d284fab7e4dd9846f19a3710558efde0d2dfd05897f3eeb9aba.svg" alt=""&gt;
      &lt;/a&gt;
    
  &lt;/div&gt;
  &lt;div class="ltag__stackexchange--body"&gt;
    
&lt;p&gt;In my case, I'm doing an &lt;em&gt;action&lt;/em&gt; each time (PullRequest) and saving the &lt;strong&gt;action results&lt;/strong&gt; in ElasticSearch.&lt;/p&gt;
&lt;p&gt;I want to build a query that will help me to get the &lt;strong&gt;results changes&lt;/strong&gt; in every &lt;em&gt;action&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;For example, the data can represent this case:&lt;/p&gt;
&lt;div class="s-table-container"&gt;
&lt;div class="table-wrapper-paragraph"&gt;&lt;table class="s-table"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PR sortable ID&lt;/th&gt;
&lt;th&gt;Results&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;…&lt;/div&gt;
    
  &lt;/div&gt;
  &lt;div class="ltag__stackexchange--btn--container"&gt;
    
      &lt;a href="https://stackoverflow.com/questions/68649757/elasticsearch-get-the-first-time-that-item-is-shown" rel="noopener noreferrer"&gt;Open Full Question&lt;/a&gt;
    
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>elasticsearch</category>
      <category>question</category>
      <category>stackoverflow</category>
    </item>
    <item>
      <title>How to setup auto semantic-release</title>
      <dc:creator>Baruch Odem</dc:creator>
      <pubDate>Tue, 27 Jul 2021 05:42:21 +0000</pubDate>
      <link>https://dev.to/baruchiro/how-to-setup-auto-semantic-release-4fd8</link>
      <guid>https://dev.to/baruchiro/how-to-setup-auto-semantic-release-4fd8</guid>
      <description>&lt;h2&gt;
  
  
  Semantic Versioning
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Semantic Versioning&lt;/em&gt; (AKA &lt;em&gt;SemVer&lt;/em&gt;) is a convention for package versions. Since it is the most used convention (AFAIK, I don't know about others...), it is well documented and widely used around the open-source, so I'm not going to describe it. You can read more &lt;a href="https://semver.org/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Semantic Release
&lt;/h2&gt;

&lt;p&gt;&lt;em&gt;Semantic Release&lt;/em&gt; is a tool to implement &lt;em&gt;SemVer&lt;/em&gt; automatically in a project.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fully automated version management and package publishing&lt;br&gt;
&lt;em&gt;from &lt;a href="https://semantic-release.gitbook.io/" rel="noopener noreferrer"&gt;Semantic Release&lt;/a&gt; docs.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In this post, I want to share with you the process of adding and configuring the &lt;code&gt;semantic-release&lt;/code&gt; tool, because I had to collect the information from multiple sources, even from the source code of the tool.&lt;/p&gt;

&lt;p&gt;Let's start.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;In this post, I assume you have&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a &lt;em&gt;NodeJS&lt;/em&gt; project (with a &lt;code&gt;package.json&lt;/code&gt; file)&lt;/li&gt;
&lt;li&gt;in a &lt;em&gt;Github&lt;/em&gt; repository&lt;/li&gt;
&lt;li&gt;with basic knowledge in &lt;em&gt;Github Actions&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;and fearlessly use CLI and read its output&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Command Line
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;semantic-release&lt;/code&gt; feels like a great tool, and it does a lot of things by default, and does them right.&lt;/p&gt;

&lt;p&gt;The first thing you want to do is to run the tool, just like that. Don't worry, it will identify that you're not in a CI environment, and it will automatically run on &lt;em&gt;dry&lt;/em&gt; mode.&lt;/p&gt;

&lt;p&gt;In your project folder, run &lt;code&gt;npx semantic-release&lt;/code&gt;, it will print some beautifully organized output. Read that output.&lt;/p&gt;

&lt;p&gt;First of all, it failed because of &lt;strong&gt;missing tokens&lt;/strong&gt;, follow the links inside the errors to create the tokens.&lt;/p&gt;

&lt;p&gt;It will not create a version (dry run), and you expect one of the next messages:&lt;/p&gt;

&lt;p&gt;
  &lt;code&gt;There is no previous release, the next release version is 1.0.0&lt;/code&gt;
  &lt;p&gt;If you never published a release before (and &lt;strong&gt;release&lt;/strong&gt; means &lt;strong&gt;git tag&lt;/strong&gt;), &lt;code&gt;semantic-release&lt;/code&gt; will create a default version &lt;code&gt;1.0.0&lt;/code&gt; in any way.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;code&gt;configured to only publish from master&lt;/code&gt;
  &lt;p&gt;The whole line:  &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;This test run was triggered on the branch foo, while semantic-release is configured to only publish from master, therefore a new version won’t be published.&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will see the &lt;code&gt;semantic-release&lt;/code&gt; is triggering a version when pushing to specific branches. If you're not in the &lt;code&gt;master&lt;/code&gt; branch, the &lt;code&gt;semantic-release&lt;/code&gt; will not process your git history to create a version.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;code&gt;There are no relevant changes, so no new version is released.&lt;/code&gt;
  &lt;p&gt;Maybe you see messages about &lt;code&gt;Analyzing commit&lt;/code&gt; because you committed some changes since your last version, but eventually, the &lt;code&gt;semantic-release&lt;/code&gt; didn't find a commit message in a pattern to create a new release.&lt;/p&gt;

&lt;p&gt;We will touch on the commit messages pattern later.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;
  &lt;code&gt;Published release 1.1.0 on default channel&lt;/code&gt;
  &lt;p&gt;OK, but it did nothing because, with &lt;em&gt;dry-run mode&lt;/em&gt;, all the actions were skipped, this is just a completion message.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Commit Format
&lt;/h3&gt;

&lt;p&gt;We ran the &lt;code&gt;semantic-release&lt;/code&gt; tool with the default configurations. Before any other configuration adjustment, the most important thing you may ask is, why is &lt;code&gt;semantic-release&lt;/code&gt; analyzing my commits but &lt;code&gt;There are no relevant changes&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;That is because &lt;code&gt;semantic-release&lt;/code&gt; uses &lt;a href="https://semantic-release.gitbook.io/semantic-release/#commit-message-format" rel="noopener noreferrer"&gt;commit message format&lt;/a&gt; to decide if and what version should be bumped.&lt;/p&gt;

&lt;p&gt;Try to commit with the message &lt;code&gt;perf(pencil): remove graphiteWidth option&lt;/code&gt; and see if now it's deciding to bump your version.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration
&lt;/h3&gt;

&lt;p&gt;I saw the &lt;a href="https://semantic-release.gitbook.io/semantic-release/#commit-message-format" rel="noopener noreferrer"&gt;default commit format (Angular Conventions)&lt;/a&gt; and I felt it will add overhead and will be less readable, and it is not worth the time I'm saving with automatic releasing. I wanted to change the commit format.&lt;/p&gt;

&lt;p&gt;To do that, we need to &lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/configuration" rel="noopener noreferrer"&gt;configure&lt;/a&gt; the &lt;code&gt;semantic-release&lt;/code&gt;, and since any configuration section will override the default configuration we used so far, I think the best idea is first to configure the default configuration explicitly, and then start to adjust it.&lt;/p&gt;

&lt;p&gt;The default configuration for the relevant sections (in &lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/configuration#configuration-file" rel="noopener noreferrer"&gt;&lt;code&gt;release.config.js&lt;/code&gt;&lt;/a&gt; format) is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;+([0-9])?(.{+([0-9]),x}).x&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;master&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;next-major&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;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;beta&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;prerelease&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="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="s2"&gt;alpha&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;prerelease&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/commit-analyzer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/release-notes-generator&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/npm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/github&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;ul&gt;
&lt;li&gt;&lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/configuration#branches" rel="noopener noreferrer"&gt;Default &lt;code&gt;branches&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://semantic-release.gitbook.io/semantic-release/usage/plugins#default-plugins" rel="noopener noreferrer"&gt;Default &lt;code&gt;plugins&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Branch Configuration
&lt;/h4&gt;

&lt;p&gt;The first configuration I wanted to change is the &lt;code&gt;branches&lt;/code&gt;. For me and for now, I just need to trigger the release on the &lt;code&gt;master&lt;/code&gt; branch, you can see how simple is the, just &lt;code&gt;branches: ['master']&lt;/code&gt; instead of the current config.&lt;/p&gt;


&lt;h5&gt;
  
  
  So far so good?
&lt;/h5&gt;

&lt;p&gt;You have that configuration, you may push and start using automatic release. What else?&lt;/p&gt;

&lt;p&gt;For me, I wanted to take it few steps forward, to&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use more convenient and readable commit messages.&lt;/li&gt;
&lt;li&gt;Set the commit message just before finishing the PR, and not on each commit.&lt;/li&gt;
&lt;li&gt;Manage a &lt;code&gt;CHANGELOG&lt;/code&gt; file.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Bonus:&lt;/em&gt; Tweet about the new version&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's continue.&lt;/p&gt;
&lt;h2&gt;
  
  
  Custom Commit Message Convention
&lt;/h2&gt;

&lt;p&gt;The default plugin &lt;a href="https://github.com/semantic-release/commit-analyzer" rel="noopener noreferrer"&gt;&lt;code&gt;@semantic-release/commit-analyzer&lt;/code&gt;&lt;/a&gt; is responsible to analyze the commit message, and it is configured by two settings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;em&gt;convention&lt;/em&gt; (&lt;code&gt;preset&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;rules&lt;/em&gt; (&lt;code&gt;releaseRules&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;(Other options: &lt;code&gt;parserOpts&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I decided to follow the &lt;a href="https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-eslint" rel="noopener noreferrer"&gt;ESLint convention&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gh"&gt;# Format:&lt;/span&gt;

Tag: Short description (fixes #1234)

&lt;span class="gh"&gt;# Examples:&lt;/span&gt;

Build: Update Travis to only test Node 0.10 (refs #734)
Fix: Semi rule incorrectly flagging extra semicolon (fixes #840)
Upgrade: Esprima to 1.2, switch to using comment attachment (fixes #730)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This format is better, right?&lt;/p&gt;

&lt;p&gt;To use this format, we first need to select &lt;code&gt;eslint&lt;/code&gt; as our &lt;code&gt;parser&lt;/code&gt;, but surprise! It is not coming with all its default available tags (the &lt;code&gt;Build&lt;/code&gt;, &lt;code&gt;Fix&lt;/code&gt;, &lt;code&gt;Upgrade&lt;/code&gt; and more), and instead, the &lt;code&gt;@semantic-release/commit-analyzer&lt;/code&gt; &lt;a href="https://github.com/semantic-release/commit-analyzer/blob/4fa5c212ce40bd45c3f8b340d693d9b58f8a55d7/lib/default-release-rules.js#L23-L27" rel="noopener noreferrer"&gt;will handle only a four tags&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Breaking&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;release&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;major&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;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Fix&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;patch&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;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Update&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;minor&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;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;release&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;minor&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;You can keep it with this default, or if you want to add more tags, you can add your custom object to &lt;strong&gt;replace&lt;/strong&gt; the default one.&lt;/p&gt;

&lt;p&gt;For me, the &lt;code&gt;plugins&lt;/code&gt; are now:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;plugins&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/commit-analyzer&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;preset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eslint&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="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/release-notes-generator&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;preset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;eslint&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/npm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/github&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;&lt;strong&gt;Note&lt;/strong&gt; that I had to update the &lt;code&gt;@semantic-release/release-notes-generator&lt;/code&gt; settings since it is also analyzing the commits to generate the release notes.&lt;/p&gt;

&lt;p&gt;And finally, I documented the default tags in my repo, just to easily find them if I forgot.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conventional PullRequest title
&lt;/h2&gt;

&lt;p&gt;For now, you expect the contributors to use the conventional commit messages (and you may use &lt;a href="https://github.com/conventional-changelog/commitlint" rel="noopener noreferrer"&gt;commitlint&lt;/a&gt;). But you don't have to force it.&lt;/p&gt;

&lt;p&gt;First of all, you can keep it optional, and if you want to trigger a new release, make sure that one of the commits in a PR is in the convention.&lt;/p&gt;

&lt;p&gt;In my repos, I'm using two conventions, side by side:&lt;/p&gt;
&lt;h3&gt;
  
  
  Merge Commit
&lt;/h3&gt;

&lt;p&gt;If the Pull Request contains more than one change (and of course, in multiple commits), although it is not best practice, you know, a small repo without contributors... Anyway, in that case, I'm looking at the commits to see if there are &lt;em&gt;conventional commits&lt;/em&gt; there, and if so, I'm &lt;strong&gt;merging&lt;/strong&gt; the PR, and the commits will be in the &lt;code&gt;master&lt;/code&gt; branch and will trigger the release.&lt;/p&gt;
&lt;h3&gt;
  
  
  Squash Commits
&lt;/h3&gt;

&lt;p&gt;If the PR is only about one change, we don't have the commits to be conventional. Instead, we can change the &lt;strong&gt;pull request title&lt;/strong&gt; to be conventional, and &lt;strong&gt;squash&lt;/strong&gt; the pull request to be only one commit in &lt;code&gt;master&lt;/code&gt;. In &lt;em&gt;Github&lt;/em&gt;, by default, the &lt;strong&gt;pull request title becomes to be the commit message in squash merge&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;To help me to remember that, I created a &lt;em&gt;Github Actions workflow&lt;/em&gt; to validate the pull request title and comment on the PR if the title does not match my convention.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PR Title&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;types&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;opened&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;edited&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;synchronize&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;reopened&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;validate&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;deepakputhraya/action-pr-title@3864bebc79c5f829d25dd42d3c6579d040b0ef16&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Validate PR Title&lt;/span&gt;
        &lt;span class="na"&gt;continue-on-error&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;regex&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;\w+:(&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;[\w\.,]+)+(&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;\(\w+&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;#\d+\))?'&lt;/span&gt; &lt;span class="c1"&gt;# Regex the title should match.&lt;/span&gt;
          &lt;span class="na"&gt;allowed_prefixes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Breaking,Fix,Update,New'&lt;/span&gt; &lt;span class="c1"&gt;# title should start with the given prefix&lt;/span&gt;
          &lt;span class="c1"&gt;# disallowed_prefixes: 'feat/,hotfix' # title should not start with the given prefix&lt;/span&gt;
          &lt;span class="na"&gt;prefix_case_sensitive&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="c1"&gt;# title prefix are case insensitive&lt;/span&gt;
          &lt;span class="c1"&gt;# min_length: 5 # Min length of the title&lt;/span&gt;
          &lt;span class="na"&gt;max_length&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt; &lt;span class="c1"&gt;# Max length of the title&lt;/span&gt;
          &lt;span class="na"&gt;github_token&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt; &lt;span class="c1"&gt;# Default: ${{ github.token }}&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;mshick/add-pr-comment@07f690343c25a94e24a8acb70d03c86b701ae322&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Comment on PR&lt;/span&gt;
        &lt;span class="na"&gt;if&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ failure() }}&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;GITHUB_TOKEN&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.GITHUB_TOKEN }}&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;Please fix the title of this PR.&lt;/span&gt;

          &lt;span class="s"&gt;Examples:&lt;/span&gt;

          &lt;span class="s"&gt;```&lt;/span&gt;
&lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;endraw %&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;

          &lt;span class="na"&gt;Breaking&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;I broke something&lt;/span&gt;
          &lt;span class="na"&gt;Fix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;fix (fixes&lt;/span&gt; &lt;span class="c1"&gt;#1234)&lt;/span&gt;
          &lt;span class="na"&gt;Update&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;some packages updates (refs&lt;/span&gt; &lt;span class="c1"&gt;#123)&lt;/span&gt;
          &lt;span class="na"&gt;New&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Added a new feature&lt;/span&gt;
&lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="err"&gt;%&lt;/span&gt; &lt;span class="nv"&gt;raw %&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;

          &lt;span class="err"&gt;```&lt;/span&gt;

          &lt;span class="s"&gt;See more in `/docs/RELEASE.md`.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;I compared a lot of optional actions to do this validation and comment, and I'm not sure I selected the best. Please share with me your suggestions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Manage a CHANGELOG file
&lt;/h2&gt;

&lt;p&gt;There is a practice to manage a file with all the release notes, for all the versions, listed on it.&lt;/p&gt;

&lt;p&gt;Unfortunately, I can't think about a beautiful way to update the CHANGELOG without adding another commit after the release.&lt;/p&gt;

&lt;p&gt;To generate the CHANGELOG and commit it, we will add two (obvious) plugins to semantic-release: &lt;a href="https://github.com/semantic-release/changelog" rel="noopener noreferrer"&gt;&lt;code&gt;@semantic-release/changelog&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://github.com/semantic-release/git" rel="noopener noreferrer"&gt;&lt;code&gt;@semantic-release/git&lt;/code&gt;&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;plugins&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/changelog&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;changelogFile&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CHANGELOG.md&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/git&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;assets&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;CHANGELOG.md&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${nextRelease.version} CHANGELOG [skip ci]&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;${nextRelease.notes}&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@semantic-release/npm&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@semantic-release/github&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;Please note&lt;/strong&gt; the plugins are running sequentially, and you have to put the &lt;code&gt;changelog&lt;/code&gt; plugin &lt;strong&gt;before&lt;/strong&gt; the &lt;code&gt;git&lt;/code&gt; plugin.&lt;/p&gt;

&lt;p&gt;This configuration will first update the &lt;code&gt;CHANGELOG.md&lt;/code&gt; file in the local folder, and after that will commit it with a custom message, includes the &lt;code&gt;[skip ci]&lt;/code&gt;, to mark this commit as out of release process.&lt;/p&gt;
&lt;h2&gt;
  
  
  &lt;em&gt;Bonus:&lt;/em&gt; Tweet about a new release
&lt;/h2&gt;

&lt;p&gt;Now you have a fully working process to automate your release, and more than that, I hope you got enough information to continue to adjust the process to your needs.&lt;/p&gt;

&lt;p&gt;One more thing I'm doing is to &lt;a href="https://twitter.com/hashtag/send_tweet_action" rel="noopener noreferrer"&gt;tweet about new releases&lt;/a&gt;, to implement, follow the instructions in &lt;a href="https://github.com/ethomson/send-tweet-action" rel="noopener noreferrer"&gt;ethomson/send-tweet-action&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you want to get the new version number (or any other value) from &lt;code&gt;semantic-release&lt;/code&gt;, you need to put it in Environment Variables, and you can do it with &lt;a href="https://github.com/semantic-release/exec" rel="noopener noreferrer"&gt;@semantic-release/exec&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;plugins&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@semantic-release/exec&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;successCmd&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;echo"SEMVER_VERSION=${nextRelease.version}" &amp;gt; $GITHUB_ENV&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="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Last words
&lt;/h2&gt;

&lt;p&gt;While writing this post to document my process, I finally found &lt;a href="https://svdoscience.com/2020-10-31/versioning-with-semantic-release" rel="noopener noreferrer"&gt;another blog post that already documented it&lt;/a&gt;, you are welcome to use both :-).&lt;/p&gt;

&lt;p&gt;Thanks to my teammate &lt;a href="https://www.linkedin.com/in/leonid-weinberg-a45964143/" rel="noopener noreferrer"&gt;Leonid Weinberg&lt;/a&gt; who review the article to correct language errors.&lt;/p&gt;



&lt;p&gt;I implemented the process in this repo:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&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%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/baruchiro" rel="noopener noreferrer"&gt;
        baruchiro
      &lt;/a&gt; / &lt;a href="https://github.com/baruchiro/use-route-as-state" rel="noopener noreferrer"&gt;
        use-route-as-state
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Use React Router route and query string as component state
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;use-route-as-state&lt;/h1&gt;
&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Use React Router &lt;strong&gt;route&lt;/strong&gt; and &lt;strong&gt;query string&lt;/strong&gt; as component &lt;strong&gt;state&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="markdown-alert markdown-alert-warning"&gt;
&lt;p class="markdown-alert-title"&gt;Warning&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Deprecation Warning&lt;/strong&gt;: This package does not support react-router v6 (see issue &lt;a href="https://github.com/baruchiro/use-route-as-state/issues/172" rel="noopener noreferrer"&gt;#172&lt;/a&gt;).&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/use-route-as-state" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/36bcee3f077e660bdca59a4fd79d98aa7ed3e1faf2694bd7a83624306b1495c4/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f762f7573652d726f7574652d61732d73746174653f6c6f676f3d6e706d266c6162656c3d76657273696f6e" alt="npm"&gt;&lt;/a&gt;
&lt;a href="https://www.npmjs.com/package/use-route-as-state" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/176ef99f0b13f8f6cf3f707078489ac0f9cacd3376b4e3bb46f02840492ae17f/68747470733a2f2f696d672e736869656c64732e696f2f6e706d2f64772f7573652d726f7574652d61732d73746174653f6c6162656c3d6e706d" alt="npm"&gt;&lt;/a&gt;
&lt;a href="https://github.com/baruchiro/use-route-as-state/actions?query=workflow%3ARelease" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/baruchiro/use-route-as-state/workflows/Release/badge.svg" alt="Release"&gt;&lt;/a&gt;
&lt;a href="https://baruchiro.github.io/use-route-as-state/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://github.com/baruchiro/use-route-as-state/workflows/Github%20Pages/badge.svg" alt="Github Pages"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Install&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;npm install --save use-route-as-state&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Usage&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;You can see a live demo, including code, &lt;a href="https://baruchiro.github.io/use-route-as-state/" rel="nofollow noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight highlight-source-tsx notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;// URL: /:param?query=&lt;/span&gt;
&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-c1"&gt;*&lt;/span&gt; &lt;span class="pl-k"&gt;as&lt;/span&gt; &lt;span class="pl-smi"&gt;React&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"react"&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
&lt;span class="pl-k"&gt;import&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-s1"&gt;useRouteParams&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;useQueryString&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt; &lt;span class="pl-k"&gt;from&lt;/span&gt; &lt;span class="pl-s"&gt;"use-route-as-state"&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

&lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-smi"&gt;Example&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-kos"&gt;{&lt;/span&gt;
  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; param &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;setRouteParams&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;useRouteParams&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;
  &lt;span class="pl-k"&gt;const&lt;/span&gt; &lt;span class="pl-kos"&gt;[&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; query &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;,&lt;/span&gt; &lt;span class="pl-s1"&gt;setQueryParams&lt;/span&gt;&lt;span class="pl-kos"&gt;]&lt;/span&gt; &lt;span class="pl-c1"&gt;=&lt;/span&gt; &lt;span class="pl-en"&gt;useQueryString&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;;&lt;/span&gt;

  &lt;span class="pl-k"&gt;return&lt;/span&gt; &lt;span class="pl-kos"&gt;(&lt;/span&gt;
    &lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;div&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;input&lt;/span&gt;
        &lt;span class="pl-c1"&gt;value&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;span class="pl-s1"&gt;param&lt;/span&gt;&lt;span class="pl-kos"&gt;}&lt;/span&gt;
        &lt;span class="pl-c1"&gt;onChange&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; target &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-en"&gt;setRouteParams&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;param&lt;/span&gt;: &lt;span class="pl-s1"&gt;target&lt;/span&gt;&lt;span class="pl-kos"&gt;.&lt;/span&gt;&lt;span class="pl-c1"&gt;value&lt;/span&gt; &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt;&lt;span class="pl-kos"&gt;}&lt;/span&gt;
      &lt;span class="pl-c1"&gt;/&lt;/span&gt;&lt;span class="pl-c1"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="pl-c1"&gt;&amp;lt;&lt;/span&gt;&lt;span class="pl-ent"&gt;input&lt;/span&gt;
        &lt;span class="pl-c1"&gt;value&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;span class="pl-s1"&gt;query&lt;/span&gt;&lt;span class="pl-kos"&gt;}&lt;/span&gt;
        &lt;span class="pl-c1"&gt;onChange&lt;/span&gt;&lt;span class="pl-c1"&gt;=&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; target &lt;span class="pl-kos"&gt;}&lt;/span&gt;&lt;span class="pl-kos"&gt;)&lt;/span&gt; &lt;span class="pl-c1"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="pl-en"&gt;setQueryString&lt;/span&gt;&lt;span class="pl-kos"&gt;(&lt;/span&gt;&lt;span class="pl-kos"&gt;{&lt;/span&gt; &lt;span class="pl-c1"&gt;query&lt;/span&gt;: &lt;span class="pl-s1"&gt;target&lt;/span&gt;&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/baruchiro/use-route-as-state" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;And these are my configuration files:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


</description>
      <category>semver</category>
      <category>semanticrelease</category>
      <category>github</category>
      <category>npm</category>
    </item>
    <item>
      <title>How to sync component state with React Router</title>
      <dc:creator>Baruch Odem</dc:creator>
      <pubDate>Mon, 07 Sep 2020 11:01:34 +0000</pubDate>
      <link>https://dev.to/baruchiro/how-to-sync-component-state-with-router-bn7</link>
      <guid>https://dev.to/baruchiro/how-to-sync-component-state-with-router-bn7</guid>
      <description>&lt;p&gt;&lt;a href="https://www.npmjs.com/package/use-route-as-state"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pd67KxHf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/npm-use--route--as--state-informational%3Flogo%3Dnpm" alt="npm"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Use Case
&lt;/h2&gt;

&lt;p&gt;You have a webpage showing your data, and an input component that controls the filtering of that data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For example&lt;/strong&gt;, you have a simple &lt;strong&gt;list of students&lt;/strong&gt;, and a &lt;strong&gt;search box&lt;/strong&gt; that filters the list as you type.&lt;/p&gt;

&lt;p&gt;You want, of course, to make the &lt;code&gt;value&lt;/code&gt; of the input reactive, in order to change the subset of the data whenever the &lt;code&gt;value&lt;/code&gt; changes.&lt;/p&gt;

&lt;p&gt;But you also want the user to be able to &lt;strong&gt;share a link&lt;/strong&gt; to the current status of the page at any time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In our example&lt;/strong&gt;, you want the contents of the search box to be represented in the URL as well, as &lt;em&gt;Query String&lt;/em&gt;, for example.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q9rgK_9Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r6iag63d4moogzazcp5n.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q9rgK_9Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/r6iag63d4moogzazcp5n.gif" alt="searchlist2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Let's see how to make the &lt;code&gt;value&lt;/code&gt; from one component to be reactive to both &lt;strong&gt;component state&lt;/strong&gt; and &lt;strong&gt;Router&lt;/strong&gt;, with clean code.
&lt;/h5&gt;

&lt;h2&gt;
  
  
  The Simple (but complicated) Way
&lt;/h2&gt;

&lt;p&gt;We will start with the direct way. We need to &lt;strong&gt;get the data from the &lt;code&gt;route&lt;/code&gt;&lt;/strong&gt;, and &lt;strong&gt;update the route on change&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We have a few APIs (hooks) to get the data from the &lt;em&gt;Router&lt;/em&gt;. For this post I chose to use &lt;a href="https://reactrouter.com/web/example/url-params"&gt;&lt;em&gt;URL Params&lt;/em&gt;&lt;/a&gt; with &lt;a href="https://reactrouter.com/web/api/Hooks/useparams"&gt;&lt;code&gt;useParams&lt;/code&gt;&lt;/a&gt; for simpler code samples, although in a real app, &lt;em&gt;Query String&lt;/em&gt; make more sense for this kind of use case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt; that to use &lt;em&gt;URL Params&lt;/em&gt; you have to declare the params in the &lt;em&gt;Router&lt;/em&gt; &lt;code&gt;path&lt;/code&gt; prop, something like &lt;code&gt;/:param1/:param2?&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Get the data from the &lt;code&gt;route&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;When the component mounts, we need to read the &lt;em&gt;URL Params&lt;/em&gt;, in case the user gets to our component from a link that should affect the state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SearchBox&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;param1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useParams&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param1&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 this is not enough, since route changes often don't reload the page (which is good). If there is no page reload, the state won’t change because the component is already mounted.&lt;/p&gt;

&lt;p&gt;We need to define the &lt;em&gt;URL Param&lt;/em&gt; change as an effect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SearchBox&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;param1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useParams&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nx"&gt;useEffect&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;setSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;param1&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;✔️ Getting the data from the &lt;code&gt;route&lt;/code&gt; is done - the &lt;strong&gt;state&lt;/strong&gt; is synced with the &lt;strong&gt;route&lt;/strong&gt; (but the &lt;strong&gt;route&lt;/strong&gt; is not synced with the &lt;strong&gt;state&lt;/strong&gt;).&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/react-router-url-parameters-forked-1ub6s?module=/RouteParams.js&amp;amp;initialpath=/li"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h3&gt;
  
  
  Update the route on change
&lt;/h3&gt;

&lt;p&gt;Now we can update the &lt;code&gt;search&lt;/code&gt; state with &lt;code&gt;setSearch&lt;/code&gt;, but we want to keep the URL up to date with the latest &lt;code&gt;search&lt;/code&gt;, in order to allow the user to copy the URL at any time.&lt;/p&gt;

&lt;p&gt;The only way (that I know) to change the URL with &lt;em&gt;React Router&lt;/em&gt; is with the &lt;a href="https://reactrouter.com/web/api/history"&gt;&lt;code&gt;history&lt;/code&gt; API&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;SearchBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Code from previous examples&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;input&lt;/span&gt;
        &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="na"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&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;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SearchList&lt;/span&gt; &lt;span class="na"&gt;search&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;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;✔️ Update the route on change is done - change the &lt;code&gt;route&lt;/code&gt; instead of the &lt;code&gt;state&lt;/code&gt;, and the &lt;code&gt;state&lt;/code&gt; will get updated from the &lt;code&gt;useEffect&lt;/code&gt; hook.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/react-router-url-parameters-forked-dk35u?module=/RouteParams.js&amp;amp;initialpath=/li"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Interim conclusions
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It is working very well in our simple example (&lt;strong&gt;even better than I thought!&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;To use the &lt;code&gt;route&lt;/code&gt; as our &lt;code&gt;state&lt;/code&gt;, we used &lt;strong&gt;four&lt;/strong&gt; hooks (&lt;code&gt;useParams&lt;/code&gt;, &lt;code&gt;useState&lt;/code&gt;, &lt;code&gt;useHistory&lt;/code&gt; and &lt;code&gt;useEffect&lt;/code&gt;) instead of &lt;strong&gt;one&lt;/strong&gt; hook to get the &lt;code&gt;state&lt;/code&gt; and a method to update it.&lt;/li&gt;
&lt;li&gt;We will need &lt;strong&gt;more and more code&lt;/strong&gt; if we want to use &lt;em&gt;Query Params&lt;/em&gt; or if we want the &lt;code&gt;history.replace&lt;/code&gt; function call to be more generic with the &lt;code&gt;path&lt;/code&gt; argument.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Actually, the solution seems very simple at this point.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Spoiler&lt;/strong&gt;- I created a package that implements this solution.&lt;br&gt;
I must share that I wonder if I would have created this package if I had written the article earlier, and understood that the solution is simple and required.&lt;br&gt;
In any case, I felt a lack of idea-sharing of this solution, so I think it is worth writing the post and creating the package.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We need to hide all this logic in a &lt;em&gt;custom hook&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Organize the code
&lt;/h2&gt;

&lt;p&gt;Let's move all the code to a dedicated function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useCustomParams&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;param1&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useParams&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;setSearch&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useState&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;history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useHistory&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&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;setSearch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;param1&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;param1&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;replace&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;newParam&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;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;newParam&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;search&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;replace&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;blockquote&gt;
&lt;p&gt;You don't really need the &lt;code&gt;state&lt;/code&gt; here, because you have a closed flow from &lt;code&gt;useParams&lt;/code&gt; to the component, then with &lt;code&gt;history&lt;/code&gt; back to the &lt;code&gt;useParams&lt;/code&gt;.&lt;br&gt;
But you will need it for the &lt;em&gt;Query String&lt;/em&gt; case.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;All that is left is not to be dependent on the &lt;code&gt;path&lt;/code&gt; or specific &lt;em&gt;URL Param&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;useCustomParams&lt;/span&gt; &lt;span class="o"&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="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useRouteMatch&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;history&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useHistory&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;updateParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;updatedParams&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="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;assign&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updatedParams&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generatePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;params&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;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateParams&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;I don't know the specific &lt;code&gt;path&lt;/code&gt; or &lt;code&gt;params&lt;/code&gt;, I just take, update and push them again.&lt;/p&gt;

&lt;p&gt;&lt;iframe src="https://codesandbox.io/embed/react-router-url-parameters-forked-6d236?module=/RouteParams.js&amp;amp;initialpath=/li"&gt;
&lt;/iframe&gt;
&lt;/p&gt;




&lt;p&gt;After going through this process myself, and seeing that there was a lack of information on this subject, I created an npm package called &lt;a href="https://www.npmjs.com/package/use-route-as-state"&gt;&lt;code&gt;use-route-as-state&lt;/code&gt;&lt;/a&gt; that implements the solution described in the article.&lt;/p&gt;

&lt;p&gt;You are welcome to use and contribute!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.npmjs.com/package/use-route-as-state"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pd67KxHf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/npm-use--route--as--state-informational%3Flogo%3Dnpm" alt="npm"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://github.com/baruchiro/use-route-as-state"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PMlewCMm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://img.shields.io/badge/Github-use--route--as--state-181717%3Flogo%3Dgithub" alt="Github"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks to &lt;a href="https://github.com/brafdlog"&gt;@brafdlog&lt;/a&gt; for linguistic editing and suggestions.&lt;/p&gt;

</description>
      <category>react</category>
      <category>npm</category>
    </item>
    <item>
      <title>Final Project - Hardware Recommendation</title>
      <dc:creator>Baruch Odem</dc:creator>
      <pubDate>Thu, 21 May 2020 13:45:49 +0000</pubDate>
      <link>https://dev.to/baruchiro/final-project-hardware-recommendation-4l3i</link>
      <guid>https://dev.to/baruchiro/final-project-hardware-recommendation-4l3i</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;This document requires proofreading in English, thank you!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Hardware Recommendation
&lt;/h2&gt;

&lt;p&gt;I am a programmer, but for the family and friends I also help with computer repair. Over the time I collected more and more used hardware components such as Memory sticks and HDDs, and when I took care of a friend or family laptop, I also added it a used component (if it was suitable).&lt;/p&gt;

&lt;p&gt;Also, as the Hardware Champion, I was also asked to recommend which new computer to buy.&lt;/p&gt;

&lt;p&gt;So I had two problems:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;As the number of the used hardware grows, how can I know if I have a component to upgrade a specific laptop?&lt;/li&gt;
&lt;li&gt;Can I trust my suggestions for new computers, if I don't track on the market updates, and if I don't know what are the Designer user needs?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These two questions lead me to try to implement a recommendation system for computer upgrading or buying.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Spoiler:&lt;/strong&gt; I didn't finish the system, but if someone wants to build one, I will be happy to join!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I started to define the project with the &lt;em&gt;Lean Canvas Model&lt;/em&gt;, I'm really suggesting you take this pattern seriously. We all know how many ideas and startup didn't even start, and not talking about finishing because we think our idea is huge, but we don't have actually measurement tools to validate that. So please use the &lt;em&gt;Lean Canvas Model&lt;/em&gt; to stay focused and adjust your project in any step!&lt;/p&gt;

&lt;p&gt;The main problems that the project will solve are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Peoples want to upgrade their computer or buy a new one, but they didn't know &lt;strong&gt;which&lt;/strong&gt; hardware component &lt;strong&gt;effect&lt;/strong&gt; on which parameter!&lt;br&gt;&lt;br&gt;
For example, someone can think that the new processor will help the computer to run faster, but he has an HDD disk, so the computer will still to be slowly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Peoples want to buy a computer for their needs, but they didn't know &lt;strong&gt;what their needs are!&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
For example, a student wants to buy a computer for learning Architecture. He knows which software he will be going to use, but he won't know if he needs a good processor or a lot of memory.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In the &lt;em&gt;Lean Canvas Model&lt;/em&gt; there are more three steps, and the central one is the &lt;strong&gt;Unique Value Proposition&lt;/strong&gt;, but I will skip on them to the &lt;strong&gt;Solution&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Collect Hardware Information from users and give them an upgrade recommendation, collect the Hardware Information to your recommendation system.&lt;/li&gt;
&lt;li&gt;Create an informative survey and generate an answer by calculating the user requirement, user personal details, and output from the recommendation system.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that even the main goal of the 1st is to collect the data, you have to give a value to the user, otherwise, he will not give you any data.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Link to Code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://baruchiro.github.io/HWRecommendation-WebAPI/"&gt;Landing Page&lt;/a&gt;&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/baruchiro"&gt;
        baruchiro
      &lt;/a&gt; / &lt;a href="https://github.com/baruchiro/HWRecommendation-WebAPI"&gt;
        HWRecommendation-WebAPI
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Server Side Web API for all API requests
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;



&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/baruchiro"&gt;
        baruchiro
      &lt;/a&gt; / &lt;a href="https://github.com/baruchiro/HWRecommendation-local"&gt;
        HWRecommendation-local
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Desktop script to fetch system information and get hardware recommendation
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  How I built it
&lt;/h2&gt;

&lt;p&gt;As I said, I didn't complete the system, so there is no complete software architecture map here, so you've earned it, otherwise, it was boring.&lt;/p&gt;

&lt;p&gt;In this project I took the opportunity to try two new technologies from Microsoft. &lt;code&gt;C#&lt;/code&gt; is my native language, and I actually love the new Microsoft (I think anyone who insists on staying prejudiced loses).&lt;/p&gt;

&lt;p&gt;The two new technologies are &lt;em&gt;Microsoft Bot Framework&lt;/em&gt; and &lt;em&gt;ML.NET&lt;/em&gt; ("New", as of the end of 2018)&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I've learned and dealt with a lot of things since then, so I can't remember all the details. &lt;br&gt;
During the development period, I wanted to write an article about my experiences with these new systems, but in those days I had hard writing in English. (Even now my English is not good, but at least it's not hard for me to write :-))&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Microsoft Bot Framework
&lt;/h3&gt;

&lt;p&gt;This system felt good. In those days, I started to love the idea of API, the idea of writing a system to expose the data and action, and then write any type of interfaces (CLI, web app, bots) to interact with the API.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Bot Framework&lt;/em&gt; is based on &lt;em&gt;ASP.NET&lt;/em&gt;, so it is just another controller that you can add to your existing &lt;em&gt;ASP.NET Web API&lt;/em&gt; (At the time it seemed right to me. Now I understand that it has no meaning).&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;Bot Framework&lt;/em&gt; wants to be an endpoint from all the bot systems (Telegram, Facebook, etc), and it was such a comfortable system. It has also an "Emulator", you can try your bot easily with a local tool, so it was excellent.&lt;/p&gt;

&lt;p&gt;Unfortunately, I missed the opportunity to offer improvements. I solved some problems and invented 2-3 patterns to reuse code and solve some other annoying design problems, but as I said, in those days it was harder for me to speak English.&lt;/p&gt;

&lt;p&gt;At least I've contributed some code for testing:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/microsoft/botbuilder-dotnet/pull/1922"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg"&gt;
      &lt;span class="issue-title"&gt;
        Add AssertReplyContain
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#1922&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/baruchiro"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--msZv0uTT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars2.githubusercontent.com/u/17686879%3Fv%3D4" alt="baruchiro avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/baruchiro"&gt;baruchiro&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/microsoft/botbuilder-dotnet/pull/1922"&gt;&lt;time&gt;May 21, 2019&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      
    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/microsoft/botbuilder-dotnet/pull/1922"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;blockquote&gt;
&lt;p&gt;Edit: Funny thing! I didn't remember if and where I wrote my conclusions from the &lt;em&gt;Bot Framework&lt;/em&gt; experience, but when I edited this &lt;em&gt;DEV.to&lt;/em&gt; profile I found a draft about that! &lt;br&gt;
I don't know if it is still relevant, if so, I will love to get help posting it. &lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="/baruchiro" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q-L4gLsF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://res.cloudinary.com/practicaldev/image/fetch/s--JShl3YU9--/c_fill%2Cf_auto%2Cfl_progressive%2Ch_150%2Cq_auto%2Cw_150/https://dev-to-uploads.s3.amazonaws.com/uploads/user/profile_image/156174/83c41e13-56fd-456f-8c8c-b7c45adfc2ca.jpeg" alt="baruchiro image"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/baruchiro/bot-framework-net-design-decisions-5gl1" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Bot Framework .NET design decisions&lt;/h2&gt;
      &lt;h3&gt;Baruch Odem ・ May 21 ・ 5 min read&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#botframework&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#netcore&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#aspnet&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  ML.NET
&lt;/h3&gt;

&lt;p&gt;In contrast to the &lt;em&gt;Bot Framework&lt;/em&gt; with the potential to improve, the &lt;em&gt;ML.NET&lt;/em&gt; was very disappointing.&lt;/p&gt;

&lt;p&gt;I played with ML with &lt;code&gt;python&lt;/code&gt; before, and compared to the dynamization in &lt;code&gt;python&lt;/code&gt;, &lt;code&gt;C#&lt;/code&gt; was disturbed. What is one of the big changes between &lt;code&gt;python&lt;/code&gt; and &lt;code&gt;C#&lt;/code&gt;? Right! the &lt;strong&gt;Typing System&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In ML, before you doing your magic, or even before you give the algorithm or the library to do its magic, you have to transform and clean your data. This is the real work on ML, at least from my point of view as a developer who has just experimented.&lt;/p&gt;

&lt;p&gt;If you writing in &lt;code&gt;python&lt;/code&gt;, do any transform you want, and get the transformed data when you want to, the transformed data will be different type from the input (for example, you transformed strings to numbers), and &lt;code&gt;python&lt;/code&gt; don't do a type validation if it not have to, so print your data and see it state every step you want!&lt;/p&gt;

&lt;p&gt;But in &lt;em&gt;ML.NET&lt;/em&gt;... Oh, it was horrible!&lt;/p&gt;

&lt;p&gt;First of all, I built a whole system to flatten complex objects and convert then to a very short list of types that can be input to the &lt;em&gt;ML.NET&lt;/em&gt;, I think it was in &lt;a href="https://github.com/baruchiro/HWRecommendation-WebAPI/blob/master/RecommendationAlgorithms/AlgorithmManager/Extensions/TypeExtensions.cs"&gt;this file&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Then, I started to transform my data. There was a good pattern of "pipeline", you connect one pipeline to another to stream the information from one transformation to another. &lt;strong&gt;But you always have to be aware of the type of the current state of the data!&lt;/strong&gt;. If I remember correctly, the pipelines connected each other with a kind of limitation about the expected output and input type.&lt;/p&gt;

&lt;p&gt;Even if I don't remember correctly, for sure you want to see how the data looks like after some transformations, to validate you are on the right way. So gues what? &lt;strong&gt;You need a type!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes! If you want to see how the data looks like after all your transformation, before the real algorithm transformation, you have to represent the expected output with Class. You find yourself trying to do all the transformations in your head, in order to represent the expected output in a Class, all this to get a snapshot of the transformed data, after you did all this in your head, and absolutely missed some edge cases.&lt;/p&gt;

&lt;p&gt;This is the stage that broke me.&lt;/p&gt;

&lt;p&gt;And my issue is still opened:&lt;/p&gt;


&lt;div class="ltag_github-liquid-tag"&gt;
  &lt;h1&gt;
    &lt;a href="https://github.com/dotnet/machinelearning/issues/3829"&gt;
      &lt;img class="github-logo" alt="GitHub logo" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vJ70wriM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://practicaldev-herokuapp-com.freetls.fastly.net/assets/github-logo-ba8488d21cd8ee1fee097b8410db9deaa41d0ca30b004c0c63de0a479114156f.svg"&gt;
      &lt;span class="issue-title"&gt;
        Support dynamic types when working with IDataView
      &lt;/span&gt;
      &lt;span class="issue-number"&gt;#3829&lt;/span&gt;
    &lt;/a&gt;
  &lt;/h1&gt;
  &lt;div class="github-thread"&gt;
    &lt;div class="timeline-comment-header"&gt;
      &lt;a href="https://github.com/baruchiro"&gt;
        &lt;img class="github-liquid-tag-img" src="https://res.cloudinary.com/practicaldev/image/fetch/s--msZv0uTT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://avatars2.githubusercontent.com/u/17686879%3Fv%3D4" alt="baruchiro avatar"&gt;
      &lt;/a&gt;
      &lt;div class="timeline-comment-header-text"&gt;
        &lt;strong&gt;
          &lt;a href="https://github.com/baruchiro"&gt;baruchiro&lt;/a&gt;
        &lt;/strong&gt; posted on &lt;a href="https://github.com/dotnet/machinelearning/issues/3829"&gt;&lt;time&gt;Jun 05, 2019&lt;/time&gt;&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag-github-body"&gt;
      &lt;h3&gt;
&lt;span class="octicon octicon-link"&gt;&lt;/span&gt;Issue&lt;/h3&gt;
&lt;p&gt;I want to read my data from the &lt;code&gt;.csv&lt;/code&gt; file. I think it may be done without strongly-typing my objects. In C#, we have two potential abilities: &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/anonymous-types" rel="nofollow"&gt;&lt;em&gt;Anonymous Types&lt;/em&gt;&lt;/a&gt; and &lt;a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/types/using-type-dynamic" rel="nofollow"&gt;&lt;em&gt;Dynamic Types&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I tried to check how the existing code could be adapted, but I could not fully understand the code.&lt;/p&gt;

    &lt;/div&gt;
    &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/dotnet/machinelearning/issues/3829"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;And these are &lt;a href="https://github.com/dotnet/machinelearning/issues?q=author%3Abaruchiro+"&gt;my other issues&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Thoughts / Feelings / Stories
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Github Student Pack
&lt;/h3&gt;

&lt;p&gt;I used &lt;em&gt;Github Sdutent Pack&lt;/em&gt; to easily freely use &lt;em&gt;Azure&lt;/em&gt;. In the &lt;em&gt;Microsoft&lt;/em&gt; ecosystem, you can easily create an end-to-end development environment, so I developed in my local &lt;em&gt;Visual Studio&lt;/em&gt;, then, from the &lt;em&gt;Visual Studio&lt;/em&gt; I configured the CI/CD pipelines in &lt;em&gt;Azure DevOps&lt;/em&gt;, and from there, I published to &lt;em&gt;Azure&lt;/em&gt; without testing my time in configuring a cloud systems.&lt;/p&gt;

&lt;p&gt;So when my class friends had to display everything on their laptops, include demo and let peoples to all wait for their laptop to be available, I just had to give them QR Code to experiment on their own.&lt;br&gt;
In other words, &lt;strong&gt;I was in production&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Today
&lt;/h3&gt;

&lt;p&gt;Now, as I write this article, I go back to that period (just a year ago), and I realize that I would have done things completely differently.&lt;/p&gt;

&lt;p&gt;In the last few months I learned so much new things and architectures, so there are some things I would have done otherwise.&lt;/p&gt;

&lt;h4&gt;
  
  
  Doing one thing
&lt;/h4&gt;

&lt;p&gt;In Agile world, we need to always give a value. Sure, you need some infrastructure to start giving a value, but the thout about my project is that I had a hidden propose in this project. I wanted to index all my hardware components.&lt;/p&gt;

&lt;p&gt;Remember my goals at the beginning of the post? Is that part of the goal?&lt;/p&gt;

&lt;p&gt;No.&lt;/p&gt;

&lt;p&gt;If you trying to do multiple things at once, you disperse and you have nothing left.&lt;/p&gt;

&lt;h4&gt;
  
  
  Microservices
&lt;/h4&gt;

&lt;p&gt;From above:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So it is just another controller that you can add to your existing &lt;em&gt;ASP.NET Web API&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you creating a one project for all your needs, you can't change things easly.&lt;/p&gt;

&lt;p&gt;After realizing that &lt;em&gt;ML.NET&lt;/em&gt; can't give me what I need, I thought to use &lt;code&gt;python&lt;/code&gt;, but the cost of integrating the &lt;code&gt;python&lt;/code&gt; code to my project was expensive. (I still used &lt;code&gt;python&lt;/code&gt; for the preparation transformations).&lt;/p&gt;

&lt;p&gt;If you working with &lt;em&gt;Microservices&lt;/em&gt;, you have a contract and way to communicate between the services, and since each service need to do one thing, if the service not meet your needs, you can easily implement another one, in another technology, that will replace the existed.&lt;/p&gt;

&lt;p&gt;Each service is small &lt;strong&gt;and independent&lt;/strong&gt;, so it's cheap to replace it.&lt;/p&gt;

</description>
      <category>octograd2020</category>
      <category>githubsdp</category>
      <category>botframework</category>
      <category>mlnet</category>
    </item>
    <item>
      <title>Bot Framework .NET design decisions</title>
      <dc:creator>Baruch Odem</dc:creator>
      <pubDate>Thu, 21 May 2020 13:13:01 +0000</pubDate>
      <link>https://dev.to/baruchiro/bot-framework-net-design-decisions-5gl1</link>
      <guid>https://dev.to/baruchiro/bot-framework-net-design-decisions-5gl1</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Hi, this post was written a long ago, and it waited for review, because my English is not so good. &lt;br&gt;
So it not posted at all. &lt;br&gt;
Now I found it as a draft, and I posted a new post, so I also releasing this post, and maybe it is not relevant anymore, so please tell me if you think it is deprecated.&lt;/p&gt;
&lt;/blockquote&gt;


&lt;div class="ltag__link"&gt;
  &lt;a href="/baruchiro" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&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%2Fuser%2Fprofile_image%2F156174%2F83c41e13-56fd-456f-8c8c-b7c45adfc2ca.jpeg" alt="baruchiro"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="/baruchiro/final-project-hardware-recommendation-4l3i" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Final Project - Hardware Recommendation&lt;/h2&gt;
      &lt;h3&gt;Baruch Odem ・ May 21 '20&lt;/h3&gt;
      &lt;div class="ltag__link__taglist"&gt;
        &lt;span class="ltag__link__tag"&gt;#octograd2020&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#githubsdp&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#botframework&lt;/span&gt;
        &lt;span class="ltag__link__tag"&gt;#mlnet&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


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

&lt;ul&gt;
&lt;li&gt;Knowledge of &lt;em&gt;ASP.NET Core&lt;/em&gt; project structure.&lt;/li&gt;
&lt;li&gt;Knowledge of developing with &lt;em&gt;Bot Framework&lt;/em&gt; in &lt;em&gt;C#&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;In my final project at the college, I write a bot with Microsoft Bot Framework on ASP.NET Core.&lt;/p&gt;

&lt;p&gt;I think Microsoft has a lot of good things and lots of pretty things that are open source. The Bot Framework is a very good idea, but something is not baked there.&lt;/p&gt;

&lt;p&gt;In order to write a well-designed code, and avoid from duplicated code, I had to make some decisions that seemed not to have been included in the original documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  apology
&lt;/h2&gt;

&lt;p&gt;This post can seem obvious to you. The problem is that it's been a while since I touched the code, and by the time I remember the more serious things, I had to start from somewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  Plug &amp;amp; Play
&lt;/h2&gt;

&lt;p&gt;In C#, the most used way to implement a bot with Bot Framework is to add it as middleware in ASP.NET Core app, and that's my case.&lt;/p&gt;

&lt;p&gt;Looking forward, if we want to use that bot in a different place, We will receive his logic, but also his WebAPI infrastructure. So if now we think about the option of publishing our bot as nuget, for integrate it with &lt;strong&gt;more then one project&lt;/strong&gt;, we may think about writing the bot only, in a project of its own.&lt;/p&gt;

&lt;h3&gt;
  
  
  The project
&lt;/h3&gt;

&lt;p&gt;The first step- writing the bot in its own project, is very straight. A bot is just a class that implements the &lt;a href="https://github.com/Microsoft/botbuilder-dotnet/blob/master/libraries/Microsoft.Bot.Builder/IBot.cs" rel="noopener noreferrer"&gt;&lt;code&gt;IBot&lt;/code&gt;&lt;/a&gt; interface, with one method:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Copyright (c) Microsoft Corporation. All rights reserved.&lt;/span&gt;
&lt;span class="c1"&gt;// Licensed under the MIT License.&lt;/span&gt;

&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.Bot.Builder&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;IBot&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;OnTurnAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ITurnContext&lt;/span&gt; &lt;span class="n"&gt;turnContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;CancellationToken&lt;/span&gt; &lt;span class="n"&gt;cancellationToken&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CancellationToken&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;Of course, all the states and accessors (&lt;a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.bot.builder.conversationstate" rel="noopener noreferrer"&gt;&lt;code&gt;ConversationState&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.bot.builder.istatepropertyaccessor-1" rel="noopener noreferrer"&gt;&lt;code&gt;IStatePropertyAccessor&amp;lt;T&amp;gt;&lt;/code&gt;&lt;/a&gt;) will be in the Bot project.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The rule of thumb&lt;/strong&gt; is that things that the bot needs &lt;strong&gt;only for its logic&lt;/strong&gt;, and are independent of the environment in which it runs, should be in its project. (Except when you want your bot to be more configurable, but that is not the subject of this post). But things that &lt;strong&gt;depend on the environment&lt;/strong&gt; in which the bot runs, such as things that belong to the Console Application against things that are relevant to the Web API, or a file system, a database, etc., will be injected into the bot from the outside.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How?&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The extension method(s)
&lt;/h3&gt;

&lt;p&gt;We will create an Extension Method for the to extend the functionality of ASP.NET, but leave the implementation in our project.&lt;/p&gt;

&lt;p&gt;The bot definition is made by code like the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddBot&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RecommendationBot&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;secretKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"botFileSecret"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;botFilePath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetSection&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"botFilePath"&lt;/span&gt;&lt;span class="p"&gt;)?.&lt;/span&gt;&lt;span class="n"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// Loads .bot configuration file and adds a singleton that your Bot can access through dependency injection.&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;botConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;BotConfiguration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;botFilePath&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;@"Echo.bot"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;secretKey&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sp&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
                    &lt;span class="n"&gt;botConfig&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt;
                    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="s"&gt;$"The .bot configuration file could not be loaded. (&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;botFilePath&lt;/span&gt; &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="s"&gt;@"Echo.bot"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;)"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

    &lt;span class="c1"&gt;// Retrieve current endpoint.&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;IsProduction&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s"&gt;"production"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"development"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;botConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FirstOrDefault&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Type&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"endpoint"&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="n"&gt;environment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(!(&lt;/span&gt;&lt;span class="n"&gt;service&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="n"&gt;EndpointService&lt;/span&gt; &lt;span class="n"&gt;endpointService&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The .bot file does not contain an endpoint."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CredentialProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;SimpleCredentialProvider&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;endpointService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AppId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endpointService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AppPassword&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Creates a logger for the application to use.&lt;/span&gt;
    &lt;span class="n"&gt;ILogger&lt;/span&gt; &lt;span class="n"&gt;logger&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;LoggerFactory&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;CreateLogger&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RecommendationBot&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Catches any errors that occur during a conversation turn and logs them.&lt;/span&gt;
    &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OnTurnError&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LogError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Exception caught : &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SendActivityAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Sorry, it looks like something went wrong."&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="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IStorage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MemoryStorage&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StateManager&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(At the time of writing, version 4.3 was released. In this version, the configuration is simpler and based on Dependency Injection.)&lt;/p&gt;

&lt;p&gt;In a regular project, the &lt;code&gt;services&lt;/code&gt; variable is the variable obtained as a parameter in the function &lt;code&gt;public void ConfigureServices(IServiceCollection services)&lt;/code&gt; in the &lt;code&gt;Startup&lt;/code&gt; class. But since we don't want all of this code to be in the &lt;code&gt;Startup&lt;/code&gt; class, which is a class of the project that &lt;strong&gt;uses&lt;/strong&gt; the bot, we can easily create an Extension Method for the &lt;code&gt;IServiceCollection&lt;/code&gt; object, &lt;strong&gt;within the bot project&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BotRegistrationExtension&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;AddOurBot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IHostingEnvironment&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddBot&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RecommendationBot&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Code from above&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;

        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IStorage&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MemoryStorage&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddSingleton&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;StateManager&lt;/span&gt;&lt;span class="p"&gt;&amp;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;Now, adding and removing the bot in the code will be very simple, all we need to do is call this function in one place in the &lt;code&gt;Startup.ConfigureServices&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddOurBot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_environment&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Shared interfaces
&lt;/h3&gt;

&lt;p&gt;Now, we've seen how to completely separate the bot from the project that uses it. In this way, we can provide the bot as Nuget Package, and hide all the implementation, so that the programmer only needs to call the Extension Method that we have set up to add the bot to its ASP.NET project.&lt;/p&gt;

&lt;p&gt;But what about the components that the robot needs to communicate with the infrastructure? We said earlier that there are things that depend on the project that runs the bot, so they will not be defined in the bot project.&lt;/p&gt;

&lt;p&gt;Assume the bot needs to save data in a database.&lt;/p&gt;

&lt;p&gt;You can probably guess the way of implementation, since this is not a special case of the bot, but rather a correct form of programming.&lt;/p&gt;

&lt;p&gt;We will create an &lt;strong&gt;interface&lt;/strong&gt; in the bot project, which will define the necessary methods, such as &lt;code&gt;Save&lt;/code&gt; and &lt;code&gt;Load&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, we can require the user to provide us with interface implementation while calling our Extension Method. We will do this by adding a &lt;strong&gt;parameter&lt;/strong&gt; to the function, or by defining the function as a &lt;strong&gt;generic&lt;/strong&gt; function:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// For provide an implementation as an argument&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;AddOurBot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IHostingEnvironment&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IDbContext&lt;/span&gt; &lt;span class="n"&gt;dbContext&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The code from above&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDbContext&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;dbContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;AddOurBot&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt; &lt;span class="n"&gt;IServiceCollection&lt;/span&gt; &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IConfiguration&lt;/span&gt; &lt;span class="n"&gt;configuration&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IHostingEnvironment&lt;/span&gt; &lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;where&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;IDbContext&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// The code from above&lt;/span&gt;
    &lt;span class="n"&gt;services&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddScoped&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IDbContext&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;T&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;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;I've shown a simple case in the Bot Framework that should be implemented more correctly.&lt;br&gt;
This example can be taken for any other project.&lt;br&gt;
In the following posts I will present things about the objects in the Bot Framework, such as &lt;code&gt;Waterfall&lt;/code&gt; and &lt;code&gt;Prompt&lt;/code&gt;, about their problems in terms of software design, and how I dealt with them.&lt;br&gt;
You are welcome to ask, comment, correct and ask for more posts.&lt;/p&gt;

&lt;p&gt;Thanks!&lt;/p&gt;

</description>
      <category>botframework</category>
      <category>netcore</category>
      <category>aspnet</category>
    </item>
    <item>
      <title>Looking for reviewer for post about Microsoft Bot Framework</title>
      <dc:creator>Baruch Odem</dc:creator>
      <pubDate>Mon, 06 May 2019 15:47:55 +0000</pubDate>
      <link>https://dev.to/baruchiro/looking-for-reviewer-for-post-about-microsoft-bot-framework-19ga</link>
      <guid>https://dev.to/baruchiro/looking-for-reviewer-for-post-about-microsoft-bot-framework-19ga</guid>
      <description>&lt;p&gt;Looking for someone to review my &lt;a href="https://github.com/baruchiro/BcsStudent/blob/master/_drafts/bot-framework.md"&gt;post&lt;/a&gt; about Microsoft Bot Framework before I publish it.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>bots</category>
    </item>
    <item>
      <title>I Computer Science Student in Israel, Ask Me Anything!</title>
      <dc:creator>Baruch Odem</dc:creator>
      <pubDate>Thu, 02 May 2019 15:44:53 +0000</pubDate>
      <link>https://dev.to/baruchiro/i-computer-science-student-in-israel-ask-me-anything-2395</link>
      <guid>https://dev.to/baruchiro/i-computer-science-student-in-israel-ask-me-anything-2395</guid>
      <description>

</description>
      <category>ama</category>
    </item>
  </channel>
</rss>
