<?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: Žiga Miklič</title>
    <description>The latest articles on DEV Community by Žiga Miklič (@zigamiklic).</description>
    <link>https://dev.to/zigamiklic</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%2F126698%2F2e16d7b7-12e6-4cca-be9d-680a0bbc27cc.jpeg</url>
      <title>DEV Community: Žiga Miklič</title>
      <link>https://dev.to/zigamiklic</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/zigamiklic"/>
    <language>en</language>
    <item>
      <title>Why, Oh Why Was This Added?</title>
      <dc:creator>Žiga Miklič</dc:creator>
      <pubDate>Thu, 26 May 2022 16:32:02 +0000</pubDate>
      <link>https://dev.to/zigamiklic/why-oh-why-was-this-added-5ca1</link>
      <guid>https://dev.to/zigamiklic/why-oh-why-was-this-added-5ca1</guid>
      <description>&lt;p&gt;To read this post you will need to use a bit of your imagination.&lt;/p&gt;

&lt;p&gt;Suppose you are checking a component called &lt;code&gt;DatePicker&lt;/code&gt; that is built on top of a 3rd party date picker component. You are tasked to find if the component is causing problems now that you have updated another project dependency. &lt;/p&gt;

&lt;p&gt;It is a larger update, so there are some breaking changes. From the migration guide, you even know exactly what can be the cause of the issues: &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Event/stopPropagation" rel="noreferrer noopener"&gt;event.stopPropagation()&lt;/a&gt;. That is exactly why you have &lt;code&gt;DatePicker&lt;/code&gt; opened - it's using &lt;code&gt;event.stopPropagation()&lt;/code&gt; in one of its event handlers:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;function DatePicker() {
  function handleDateChange(event) {
    event.stopPropagation();
  }

  return (
    &amp;lt;ThirdPartyDatePicker
      onChange={handleDateChange}
    /&amp;gt;
  );
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;A simplified version of the component&lt;/p&gt;

&lt;p&gt;But, why was that &lt;code&gt;event.stopPropagation()&lt;/code&gt; added? To know if the migration broke something, you first have to find the reason why it exists in the first place. Taking a sip of your coffee, you embark on your debugging journey.&lt;/p&gt;

&lt;h2&gt;Debugging Journey&lt;/h2&gt;

&lt;p&gt;When you remove &lt;code&gt;event.stopPropagation()&lt;/code&gt;, you don't see any difference. All the tests are passing. You check the 3rd party date picker project/documentation if there is a specific reason but return empty-handed. You then revert all the migration changes and remove &lt;code&gt;event.stopPropagation()&lt;/code&gt; in your current app version. You also don't see a noticeable difference. You start asking yourself if it serves a purpose at all.&lt;/p&gt;

&lt;p&gt;You then check the Git history and see &lt;code&gt;event.stopPropagation()&lt;/code&gt; is there since the initial version and there is no info about it in the commit message. Another dead end. Finally, you check who implemented it. Maybe they know some secret you don't. Maybe it's something super obvious that you are missing. Finally, they will solve this mystery and you will be able to go to bed peacefully tonight! Well, it turns out the original author no longer works at the company.&lt;/p&gt;

&lt;p&gt;But you are still hesitant to remove it. Surely it was not added for no reason? You don't want to &lt;a href="https://fs.blog/chestertons-fence/" rel="noreferrer noopener"&gt;make assumptions&lt;/a&gt; and repeat your &lt;a href="https://zigamiklic.com/cautionary-tale/" rel="noreferrer noopener"&gt;past mistakes&lt;/a&gt;. So you search your app where the component is used and try to spot any special use cases. And after a while you do. In one use case (out of 100+) the &lt;code&gt;DatePicker&lt;/code&gt; component is placed inside another component in which preventing event bubbling is required. To make sure you don't forget, you quickly add a comment explaining why &lt;code&gt;event.stopPropagation()&lt;/code&gt; is there. You are hopeful that it will help save time for someone in the future. That future someone might even be you.&lt;/p&gt;

&lt;p&gt;After that, you are finally able to test if the migration is causing an issue and fix it if necessary. And so you come at the end of your debugging journey. Well, sort of. You come to the end for this particular &lt;code&gt;event.stopPropagation()&lt;/code&gt;. There are still quite a few more in the codebase.&lt;/p&gt;

&lt;p&gt;You move on to the next &lt;code&gt;event.stopPropagation()&lt;/code&gt; and see that this one also does not include a comment. You read the surrounding code but again don't know why someone added it.&lt;/p&gt;

&lt;p&gt;And just like that, we are again at step 1 of our debugging journey.&lt;/p&gt;

&lt;h2&gt;Backstory&lt;/h2&gt;

&lt;p&gt;Now to give you more context.&lt;/p&gt;

&lt;p&gt;This week I was migrating our app to React 17. I suspect you might be thinking: "React 17? You do know that &lt;a href="https://reactjs.org/blog/2022/03/29/react-v18.html" rel="noreferrer noopener"&gt;React 18&lt;/a&gt; is already out, right?" I am solely to blame here. I had concerns with React 17 breaking another dependency and postponed the update several times.&lt;/p&gt;

&lt;p&gt;Nevertheless, one of the things that React 17 changes is how &lt;a href="https://reactjs.org/blog/2020/10/20/react-v17.html#changes-to-event-delegation" rel="noreferrer noopener"&gt;event delegation&lt;/a&gt; works. More specifically, React no longer attaches event handlers to the &lt;code&gt;document&lt;/code&gt; object but instead attaches them to the root DOM container.&lt;/p&gt;

&lt;p&gt;My plan for migrating to React 17 was to search our codebase for &lt;code&gt;event.stopPropagation()&lt;/code&gt; and then test the UI to make sure everything was working correctly. But while I was going through each use case, I realized just how little information &lt;code&gt;event.stopPropagation()&lt;/code&gt; provides. We usually call it at the top of event handlers without any extra info. When checking the code you know &lt;em&gt;what &lt;/em&gt;it is doing (preventing event bubbling) but you don't know &lt;em&gt;why&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Some use cases were obvious by looking at the surrounding code but for a lot of them, it took me a while to figure it out. These ambiguous use cases fell into four categories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They prevent triggering events in components nested many levels higher.&lt;/li&gt;
&lt;li&gt;They solve very specific edge cases.&lt;/li&gt;
&lt;li&gt;They prevent triggering events in 3rd party libraries.&lt;/li&gt;
&lt;li&gt;They exist for no reason.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please note that I am not writing this post to point fingers at my coworkers. I have written this post primarily for myself as I have also written many times &lt;code&gt;event.stopPropagation()&lt;/code&gt; without including a comment. I write it automatically when the need arises without giving it a second thought.&lt;/p&gt;

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

&lt;p&gt;While not commenting your &lt;code&gt;event.stopPropagation()&lt;/code&gt; calls is usually not a big deal, it may be a problem in situations like mine where I had to go over many ambiguous use cases at once. This resulted in a lot of wasted time that could be otherwise avoided if the original author added a comment.&lt;/p&gt;

&lt;p&gt;So the next time you are writing &lt;code&gt;event.stopPropagation()&lt;/code&gt;, stop and think if adding a comment where you explain why it is there would benefit a future reader. Your colleagues or your future self will be grateful that you did.&lt;/p&gt;

</description>
      <category>programming</category>
      <category>react</category>
    </item>
    <item>
      <title>Lessons Learned: The Passionate Programmer</title>
      <dc:creator>Žiga Miklič</dc:creator>
      <pubDate>Thu, 19 May 2022 13:00:25 +0000</pubDate>
      <link>https://dev.to/zigamiklic/lessons-learned-the-passionate-programmer-5ec7</link>
      <guid>https://dev.to/zigamiklic/lessons-learned-the-passionate-programmer-5ec7</guid>
      <description>&lt;p&gt;Below are 5 of my favorite lessons from the book &lt;a href="https://www.goodreads.com/book/show/6399113-the-passionate-programmer" rel="noreferrer noopener"&gt;The Passionate Programmer&lt;/a&gt; by Chad Fowler.&lt;/p&gt;

&lt;h2&gt;Learn How to Fail&lt;/h2&gt;

&lt;p&gt;Everyone makes mistakes so it's important to learn how to react when we do make a mistake:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We shouldn't hide our mistakes and instead, we should let our team know as soon as possible. Mistakes that we catch early are easier to fix and will likely have a lesser negative impact.&lt;/li&gt;
&lt;li&gt;We need to find a solution as quickly as possible. That means we should take responsibility for the issue (even if we are not 100% at fault) and start searching for a solution instead of searching for who to blame.&lt;/li&gt;
&lt;li&gt;We should propose a specific plan (step-by-step, goals) on how to fix the issue. This is especially important if the issue affects others on our team.&lt;/li&gt;
&lt;li&gt;We shouldn't be afraid to ask for help, especially if we are unsure with our proposed solution.&lt;/li&gt;
&lt;li&gt;We shouldn't panic. Panicking will not give us an advantage but will instead cause us to underperform in a situation when we need to perform our best.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Step off of the &lt;a href="https://en.wikipedia.org/wiki/Hedonic_treadmill" rel="noreferrer noopener"&gt;Hedonic Treadmill&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We all want to progress in our careers. Be it a bigger salary, a shinier title, or more responsibilities. While we should be ambitious and have goals, being too ambitious can sometimes produce negative results.&lt;/p&gt;

&lt;p&gt;When we constantly want more, we become more focused on our next job rather than our current one. And while we fantasize about our future job, we may start to produce mediocre work at our current one.&lt;/p&gt;

&lt;p&gt;When we compare our current job with a fantasized future job, our current job will always appear worse. It makes us ignore the good parts and amplify the bad parts of our current job.&lt;/p&gt;

&lt;p&gt;While it seems counterintuitive, we may produce better results by focusing on the present. With our focus on our current job, we enjoy it more. We start noticing the small (daily) wins that we would otherwise miss and feel more of an essential part of the team. As we enjoy our job more, we become more motivated and productive, which makes it more likely for us to succeed.&lt;/p&gt;

&lt;h2&gt;Make Borings Tasks Fun&lt;/h2&gt;

&lt;p&gt;We do our best work when the task is fun, exciting, or interesting. But when a task is boring, we drag our feet and as a result, produce mediocre results. Almost every job has tasks that few enjoy doing but still need to get done. These are usually tasks where we don't get to flex our creative muscles or test our skills. But what if we could make those boring tasks more fun?&lt;/p&gt;

&lt;p&gt;One way to do so is to make the boring tasks more challenging. How would we do a task if we wanted to do it "perfectly" or what if we imposed a very tight deadline?&lt;/p&gt;

&lt;p&gt;Another way to make boring tasks more fun is to turn them into a competition with our coworkers to see who can do them better.&lt;/p&gt;

&lt;h2&gt;Improve Your Writing&lt;/h2&gt;

&lt;p&gt;We write a lot during our workdays so it's a good idea to &lt;a href="https://www.julian.com/guide/write/intro" rel="noreferrer noopener"&gt;become good at it&lt;/a&gt;. This is especially important for distributed teams where we won't be effective team members if we are unable to express ourselves.&lt;/p&gt;

&lt;p&gt;Improving our writing will also make us better programmers. The ability to explain an idea and lead the reader to a logical conclusion is very similar to the ability to design a maintainable system that future developers will be able to understand.&lt;/p&gt;

&lt;p&gt;Improving our writing also saves time (and patience) as our team members don't need to guess what we meant or have to reimplement a feature because of a misunderstood of our writing.&lt;/p&gt;

&lt;h2&gt;Take One Small Step at a Time&lt;/h2&gt;

&lt;p&gt;When we are facing large, complex projects we quickly become demotivated. We become farsighted and only see the amount of work and time that it will take to fully complete the project instead of seeing all the small (easy) steps that will get us closer to finishing it.&lt;/p&gt;

&lt;p&gt;On larger projects, we don't make a lot of progress in the short term. This can make it seem like our efforts are for nothing and can lead us to abandon the project completely.&lt;/p&gt;

&lt;p&gt;The key to completing large projects is to focus on making our project better today than it was yesterday.&lt;/p&gt;

&lt;p&gt;If we work on an application with poor codebase health, the task of improving it will look daunting. Instead of focusing on the end state where the codebase is in "perfect" health, we should instead focus on making it just a &lt;a href="https://zigamiklic.com/micro-refactoring/"&gt;tiny bit better&lt;/a&gt;. We should look for easy wins in the parts of the codebase we are currently working on. See a poorly named function? Rename it. See a large section of commented-out code? Remove it. See a long class method? Refactor it into smaller, well-named methods.&lt;/p&gt;








&lt;p&gt;Do you find these lessons interesting? Well, I've got good news for you. The book contains many more such lessons (53 to be exact). It also features a couple of amazing essays by successful people from our industry, my favorite one being from the founder of GitHub. So if you are looking for a book to improve your career, this is a great choice.&lt;/p&gt;

&lt;p&gt;The post &lt;a href="https://zigamiklic.com/passionate-programmer/"&gt;Lessons Learned: The Passionate Programmer&lt;/a&gt; appeared first on &lt;a href="https://zigamiklic.com"&gt;Blog by Žiga Miklič&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>career</category>
    </item>
    <item>
      <title>Refactoring With Confidence</title>
      <dc:creator>Žiga Miklič</dc:creator>
      <pubDate>Mon, 16 May 2022 13:20:48 +0000</pubDate>
      <link>https://dev.to/zigamiklic/refactoring-with-confidence-jm8</link>
      <guid>https://dev.to/zigamiklic/refactoring-with-confidence-jm8</guid>
      <description>&lt;p&gt;Last week while I was making changes to our &lt;strong&gt;constants.js&lt;/strong&gt; file, I spotted that we could improve its maintainability and readability. But before I could put on my refactoring glasses, I first had to make sure I would not introduce any new bugs into the codebase.&lt;/p&gt;

&lt;p&gt;Because the list of constants that I would need to change was quite long, there was a high chance I would make a mistake. Our automated tests would most likely not catch the bug as our &lt;strong&gt;constants.js&lt;/strong&gt; file is not explicitly tested as it does not contain any logic. So to improve my confidence in making the changes, I first created a (throwaway) unit test. Although I generally avoid using &lt;a rel="noreferrer noopener" href="https://jestjs.io/docs/snapshot-testing"&gt;Jest snapshots&lt;/a&gt;, I think this was an ideal use case for them.&lt;/p&gt;

&lt;h2&gt;Inspecting the Problems&lt;/h2&gt;

&lt;p&gt;Let's start by taking a look at our initial constants object:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;constants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;CHANNEL_BLOG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;CHANNEL_WORDPRESS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;CHANNEL_SHOPIFY&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;CHANNEL_FACEBOOK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;CHANNEL_TWITTER&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;CHANNEL_GROUP_PERSONAL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;CHANNEL_GROUP_SOCIAL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;CHANNEL_NAMES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WordPress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Shopify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Facebook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Twitter&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;CHANNEL_ROUTES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channels/blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channels/wordpress&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channels/shopify&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channels/facebook&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channels/twitter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above object is a smaller version of the real one so it more easily illustrates all the issues that I wanted to fix:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The value of each channel is located in three or more locations. This means if we would need to change the value of a channel, we would need to make sure to do so in all locations. Spoiler alert, you will most likely miss changing one of them.&lt;/li&gt;
&lt;li&gt;The values can become out of sync as the values are not linked with each other. You may have spotted such an issue in the above example. At some point, someone removed the &lt;code&gt;CHANNEL_ARTICLE&lt;/code&gt; with the value of &lt;code&gt;4&lt;/code&gt;. They removed its definition, name, and route; but forgot to exclude it from all the channel groups (see &lt;code&gt;CHANNEL_GROUP_PERSONAL&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The channel groups are hard to read as you need to manually/mentally map a value to the corresponding channel name. This means if you want to remove the Facebook channel from the &lt;code&gt;CHANNEL_GROUP_SOCIAL&lt;/code&gt;, you first need to find out which value (&lt;code&gt;5&lt;/code&gt; or &lt;code&gt;6&lt;/code&gt;) is referring to Facebook.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Making the Improvements &lt;/h2&gt;

&lt;p&gt;An object with all the above issues fixed would look something like this:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CHANNEL_BLOG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CHANNEL_WORDPRESS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CHANNEL_SHOPIFY&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&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;CHANNEL_FACEBOOK&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CHANNEL_TWITTER&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;constants&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;CHANNEL_BLOG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CHANNEL_WORDPRESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CHANNEL_SHOPIFY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CHANNEL_FACEBOOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;CHANNEL_TWITTER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="na"&gt;CHANNEL_GROUP_PERSONAL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CHANNEL_BLOG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CHANNEL_WORDPRESS&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CHANNEL_SHOPIFY&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;CHANNEL_GROUP_SOCIAL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CHANNEL_FACEBOOK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CHANNEL_TWITTER&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;

  &lt;span class="na"&gt;CHANNEL_NAMES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CHANNEL_BLOG&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Blog&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="nx"&gt;CHANNEL_WORDPRESS&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;WordPress&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="nx"&gt;CHANNEL_SHOPIFY&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Shopify&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="nx"&gt;CHANNEL_FACEBOOK&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Facebook&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="nx"&gt;CHANNEL_TWITTER&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Twitter&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;CHANNEL_ROUTES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;CHANNEL_BLOG&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channels/blog&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="nx"&gt;CHANNEL_WORDPRESS&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channels/wordpress&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="nx"&gt;CHANNEL_SHOPIFY&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channels/shopify&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="nx"&gt;CHANNEL_FACEBOOK&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channels/facebook&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="nx"&gt;CHANNEL_TWITTER&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;channels/twitter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's look at the new object more closely:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We refactored the channel definitions into variables. This allows us to reuse them as values for other constants.&lt;/li&gt;
&lt;li&gt;We replaced the fixed values inside the channel groups. This makes it easy for someone to read what channels are in each group. The mistake mentioned above where someone forgot to remove all values of a constant also won't be possible to repeat in the future. This is because as soon as you remove a constant and don't remove all its usages, you will start seeing the &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Not_defined" rel="noreferrer noopener"&gt;ReferenceError: "x" is not defined&lt;/a&gt; error.&lt;/li&gt;
&lt;li&gt;We replaced the fixed property keys of &lt;code&gt;CHANNEL_NAMES&lt;/code&gt; and &lt;code&gt;CHANNEL_ROUTES&lt;/code&gt; with the channel variables. We did so by using &lt;a rel="noreferrer noopener" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#new_notations_in_ecmascript_2015"&gt;computed property names&lt;/a&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;As you can see, there are multiple changes that we need to do for each constant. In the case of our app where we have 30+ channels, there is a good chance that I would make a mistake while refactoring. I hope at this point you agree that the upfront investment of writing a unit test is well worth it.&lt;/p&gt;

&lt;h2&gt;Creating the Unit Test&lt;/h2&gt;

&lt;p&gt;For this task, the unit test needs to check the original object and compare it to the modified version. In our app we use &lt;a href="https://jestjs.io/" rel="noreferrer noopener"&gt;Jest&lt;/a&gt; to write our unit and integration tests.&lt;/p&gt;

&lt;p&gt;We could include the original object inside the test and use &lt;a href="https://jestjs.io/docs/expect#tomatchobjectobject" rel="noreferrer noopener"&gt;toMatchObject&lt;/a&gt; matcher but I instead opted to create a snapshot:&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;constants&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../constants&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;should match the original object&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;constants&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toMatchSnapshot&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;When we run the test for the first time, Jest will remember the object value by storing it as a snapshot. It will then use the snapshot for comparison when we run the test again.&lt;/p&gt;

&lt;p&gt;To run the test I used the following Jest CLI command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;jest contants.test.js --watch&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;--watch&lt;/code&gt; mode makes sure to automatically run the test each time we make a change.&lt;/p&gt;

&lt;p&gt;Once I had the unit test in place, I went step-by-step making small changes. If I made a mistake after a change, the unit test would let me know and point to the issue. Fixing a mistake was fast and simple. After I had made all the changes, I removed the unit test and opened a pull request.&lt;/p&gt;

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

&lt;p&gt;We need to be confident that we will not introduce any issues in our codebase when making refactorings.&lt;/p&gt;

&lt;p&gt;If the change is small and isolated (changing a variable name, fixing a typo, etc.), checking the change manually can be a valid approach.&lt;/p&gt;

&lt;p&gt;But in a lot of cases making sure a unit test is watching over our changes is the practical way to go. This is especially true in situations when making:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;large changes,&lt;/li&gt;
&lt;li&gt;changes that affect multiple parts,&lt;/li&gt;
&lt;li&gt;changes that require you to test many cases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When we are refactoring a part of the codebase that is not yet covered by an automated test, we should check to see if introducing a test to the codebase will provide value. If so, then we need to make sure to write a test that is not going to be a maintenance burden. &lt;a href="https://jestjs.io/docs/snapshot-testing" rel="noreferrer noopener"&gt;Jest snapshots&lt;/a&gt; were a great use case for this throwaway test but in a lot of cases can be a maintenance nightmare as your tests can report false negatives.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://zigamiklic.com/refactoring-with-confidence/"&gt;This post&lt;/a&gt; first appeared on &lt;a href="https://zigamiklic.com"&gt;my personal blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>testing</category>
      <category>refactoring</category>
    </item>
    <item>
      <title>A Short Cautionary Tale About Refactoring</title>
      <dc:creator>Žiga Miklič</dc:creator>
      <pubDate>Thu, 18 Mar 2021 23:18:52 +0000</pubDate>
      <link>https://dev.to/zigamiklic/a-short-cautionary-tale-about-refactoring-1gg5</link>
      <guid>https://dev.to/zigamiklic/a-short-cautionary-tale-about-refactoring-1gg5</guid>
      <description>&lt;p&gt;This week I was making changes in a part of the codebase I was unfamiliar with. While reading the code I spotted an inlined PNG image. This was not a small icon but an image of about 100kb in size. I searched the project and found the same inlined image in a couple of different components. Maybe it was because I was in a need of some coffee, but at that moment I could not think of a good reason for this approach. As the components with the inline image were quite similar, I surmised that they were copied from each other and the inline image is just one of those weird things that you find in legacy code.&lt;/p&gt;

&lt;p&gt;I decoded the embedded image from Base64 and created a separate PNG file from it. The final step was to replace the inlined image source with a relative path to the new image file. The diff for the commit was almost perfect: large red blocks of deleted code and just a few green lines of added code. A quick and easy refactoring win and a textbook example of the &lt;a href="https://wiki.c2.com/?BoyScoutRule"&gt;boy scout rule&lt;/a&gt;. Or so I thought.&lt;/p&gt;

&lt;p&gt;I took a short break and grabbed some much-needed coffee. Fast forward a few hours and I completed the task that I was originally working on. I was in the final stages of testing when I noticed a bug. At that same moment, I also realized the exact purpose of the inlined image. Can you guess?&lt;/p&gt;

&lt;p&gt;To give you more context, we use the components with the image to display error messages. The image is a cute illustration of the company mascot with the expression “Oops something went wrong”. One of the possible errors that can happen, is when the user losses their connection or goes offline. So when that happens and you render a component that still needs to download an image, the image will fail to load. Oh yeah… 🤦‍♂️&lt;/p&gt;

&lt;p&gt;I thought I had learned the hard way earlier in my career not to presume I know better than the original author. Of course, there are situations where a less experienced coder (ie. yourself from a couple of years ago) worked on a feature or where someone had to cut corners (eg. due to a deadline). But usually, there is a good reason why someone took the approach that they did.&lt;/p&gt;

&lt;p&gt;Luckily I spotted the issue before I pushed my branch. I could use &lt;code&gt;git reset --soft&lt;/code&gt; and alter my changes. I extracted the inlined image into a separate React component and used it where needed. This way we still get both benefits: the error components are much cleaner and easier to read, and the inlined image is located in one place. After that, I reapplied all the other commits. The Git history was clean and none of my coworkers were the wiser. Unless they are reading this, in which case: “Oh hey, how’s it going?” 😅&lt;/p&gt;

&lt;p&gt;I know, this bug would not be the end of the world. But this small example shows how even the best of our refactoring intentions can do more harm than good. If you find yourself looking at a piece of code that looks strange or needlessly too complex, ask your coworkers. This is especially true if the original author is still at the company. You might be missing some context and you’ll get to learn something new. Or you can indeed improve the code, in which case the original author may learn the better approach. In both cases, it’s a win. Also if there is a good reason for the current approach, document it. Add a more descriptive name or a comment to avoid confusion in the future.&lt;/p&gt;

&lt;p&gt;Learn from my small mistake and research before making refactorings. This is 10 times more important for larger changes and when editing the core files of the project. And the most important thing: don’t forget to drink some coffee before starting.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://zigamiklic.com/cautionary-tale/"&gt;This post&lt;/a&gt; first appeared on &lt;a href="https://zigamiklic.com"&gt;my personal blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>react</category>
    </item>
  </channel>
</rss>
