<?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: Petar Garžina</title>
    <description>The latest articles on DEV Community by Petar Garžina (@pgarzina).</description>
    <link>https://dev.to/pgarzina</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%2F631155%2Ff47f8a8f-3d57-4b8a-8af8-e4f3223fe19f.jpeg</url>
      <title>DEV Community: Petar Garžina</title>
      <link>https://dev.to/pgarzina</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/pgarzina"/>
    <language>en</language>
    <item>
      <title>Do you even read bro? 5 advices on reading and staying up to date</title>
      <dc:creator>Petar Garžina</dc:creator>
      <pubDate>Fri, 21 Jul 2023 08:42:06 +0000</pubDate>
      <link>https://dev.to/pgarzina/do-you-even-read-bro-5-advices-on-reading-and-staying-up-to-date-1kdo</link>
      <guid>https://dev.to/pgarzina/do-you-even-read-bro-5-advices-on-reading-and-staying-up-to-date-1kdo</guid>
      <description>&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp69te8742njxony5gve1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp69te8742njxony5gve1.jpg" alt="Do you even read meme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;small&gt;&lt;a href="https://knowyourmeme.com/memes/do-you-even-lift" rel="noopener noreferrer"&gt;https://knowyourmeme.com/memes/do-you-even-lift&lt;/a&gt; A popular meme back in the days. Used as a condescending expression to question the legitimacy of someone’s expertise around a certain topic. Do you even lift bro? &lt;/small&gt;&lt;/p&gt;

&lt;p&gt;In the last couple of interviews when we asked the candidates what they read to keep up to date with the latest tech, they had no straight answer. I was a bit saddened by that fact, so I decided to write this blog post about the struggles I experienced and how I managed to keep on reading, either books or tech blogs.&lt;/p&gt;

&lt;p&gt;This is also an extended version of the answers to questions I got asked at an IT Job Fair at our local university: &lt;em&gt;How do you maintain your professional skill?&lt;/em&gt; and &lt;em&gt;How to land your first job in IT?&lt;/em&gt; Hopefully you will find the advice that follows useful.&lt;/p&gt;

&lt;p&gt;Already tired of reading? No problem here's a tldr:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read a major introductory book&lt;/li&gt;
&lt;li&gt;Subscribe to at least one newsletter&lt;/li&gt;
&lt;li&gt;Re-read important chapters, articles or books&lt;/li&gt;
&lt;li&gt;Read a book to master the subject&lt;/li&gt;
&lt;li&gt;Find the time to read, change priorities&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The start
&lt;/h2&gt;

&lt;p&gt;To give you a bit of context, I am a software engineer with no formal college education in programming. Most of the things I know I read in books and articles, the rest I learned from online courses. I was interested in programming and went to a few public lectures and workshops and managed to publish two small Android apps. Soon I realised that without proper core knowledge and understanding of programming I would never get far. In my last year of college (in Linguistics) I was lucky enough and got an opportunity to go on a summer internship to University of Indiana, USA. My job as an intern involved a bit of programming as well since I was into Computational Linguistics. I decided to invest that summer into reading two core introductory books. The first one was a general &lt;a href="https://math.hws.edu/eck/cs124/downloads/javanotes7-linked.pdf" rel="noopener noreferrer"&gt;Introduction to Programming Using Java&lt;/a&gt; and the other was about &lt;a href="https://www.oreilly.com/library/view/android-programming-the/9780134171517/" rel="noopener noreferrer"&gt;Android Programming&lt;/a&gt;. I did spend almost all afternoons reading them, but it really paid off. That was what really got me off the ground and enabled me to move forward into the field.&lt;/p&gt;

&lt;p&gt;That brings us to advice number one, especially if you are a beginner:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Invest time in reading at least one major introductory book that covers the subject thoroughly&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Up until that point I read tutorials, watched videos and was able to muster up an application or two. But after reading 1000+ pages that went deep into the matter I finally understood a lot of the things that prior to this I was just copy pasting with little understanding on how they worked. Again, reading them was not easy. I remember keeping my finger on the Abstract class chapter and each time the abstract class would be mentioned further in the book I would have to go back and reread the chapter as it was hard for me to grasp the concept in just one go. For me, those two books enabled me to switch my profession and to land a job as a programmer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The journey
&lt;/h2&gt;

&lt;p&gt;The road ahead was paved with HTML and CSS as I moved into Web Application development and the ever changing world of Frontend development. To stay ahead of the game you had to follow an extremely broad and somehow &lt;a href="https://css-tricks.com/the-great-divide/" rel="noopener noreferrer"&gt;Greatly Divided&lt;/a&gt; field. Even if you are an UX engineer focused on design, HTML and CSS or a JavaScript engineer focused on programming, there are still a lot of topics to cover. This is where weekly digests helped a lot.&lt;br&gt;
At the beginning I was only getting &lt;a href="https://androidweekly.net/" rel="noopener noreferrer"&gt;Android Weekly&lt;/a&gt; which got replaced with &lt;a href="https://javascriptweekly.com/" rel="noopener noreferrer"&gt;JavaScript Weekly&lt;/a&gt;. Soon after I've added &lt;a href="https://medium.com/" rel="noopener noreferrer"&gt;Medium&lt;/a&gt; daily digest. But the daily digest was a bit too much and I switched it to a weekly digest as well. Later on I added &lt;a href="https://frontendfoc.us/" rel="noopener noreferrer"&gt;Frontend Focus&lt;/a&gt;, and have kept those three for more than 7 years now. &lt;br&gt;
Both JavaScript Weekly and Frontend Focus are structured in a similar way. You get a &lt;em&gt;General Articles&lt;/em&gt; section to start with, followed by a &lt;em&gt;Quick and Brief&lt;/em&gt; section outlining a couple of new things out here. After that three sections follow: &lt;em&gt;Tutorials and Articles&lt;/em&gt;, &lt;em&gt;Tools and Resources&lt;/em&gt; and the last one is &lt;em&gt;Jobs&lt;/em&gt;. I read all of the headings as they alone are informative enough to learn if a new Node version is out or an LTS for a tool came to an end. Every now and then I open a job posting or two to see how the industry standard is changing in that regard, mostly checking out the perks and the salaries. &lt;br&gt;
Each of the three serves a purpose; JavaScript Weekly is JavaScript oriented, including backend JS. Frontend Focus includes more articles about Design and UX/UI, and my Medium feed is focused on Angular. In the end I usually read just one or two articles from all three weekly digests. Of course there comes a period of time when I do less reading, my inbox gets cluttered, I skip the digest for a couple of weeks and just delete them. &lt;/p&gt;

&lt;p&gt;You don't have to subscribe to three but&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Subscribe to at least one weekly digest.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Newsletters don't require that much focus time as a book, so you can read them wherever. Drinking your morning coffee at the office or in the waiting room at the dentist. What helps a lot to stay loyal to your weekly digests is having &lt;a href="https://gmelius.com/blog/inbox-zero-gmail" rel="noopener noreferrer"&gt;Inbox Zero&lt;/a&gt; Policy. That way the digests don't get lost too quickly and it also drives you into reading them.&lt;/p&gt;

&lt;p&gt;As for the books, in the first couple of years I've read two JavaScript books: &lt;a href="https://www.manning.com/books/secrets-of-the-javascript-ninja-second-edition" rel="noopener noreferrer"&gt;Secrets of the JavaScript Ninja&lt;/a&gt; and &lt;a href="https://www.oreilly.com/library/view/mastering-modular-javascript/9781491955673/" rel="noopener noreferrer"&gt;Mastering Modular Javascript&lt;/a&gt;. The 500-pager on how to become a Ninja was useful, but how to build modular architecture with JavaScript is the one I really loved. It's a rather thin book, around 150 pages, mostly text with very little code examples. After reading this book I was like, wow, I'll have to read this book again. And so I did, a year or so after. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The main benefit of reading a good book again, particularly many years later, is that your added experience of life [work] enables you to understand what the author had in mind much more clearly. &lt;a href="https://www.dpag.ox.ac.uk/team/john-stein" rel="noopener noreferrer"&gt;Stein&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even though it takes a bit more effort, re-reading a book or at least some parts of it is essential in better understanding the topic.&lt;/p&gt;

&lt;p&gt;That would be my 3rd advice&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Re-read a chapter, an article or a book&lt;/strong&gt;&lt;br&gt;
Often, reading it once is not enough, you will deepen your understanding with the second read.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Although my transition from the initial Java/Android developer to a Web App developer went kind of smooth, I always had a feeling I was missing something. One day a colleague ordered &lt;a href="https://www.oreilly.com/library/view/javascript-the-definitive/9781491952016/" rel="noopener noreferrer"&gt;JavaScript the Definitive Guide&lt;/a&gt; and by mistake we got two copies. I was glad and I took the opportunity to finally read a JavaScript book that covers the language from A to Z. Even though years passed and I was far off into the field I thought it was not too late for me to go through the ins and outs of the language, through all the quirkiness JavaScript provides. Challenge yourself to read that core book, the one that digs deep into the matter and that will &lt;em&gt;"take your understanding and mastery to the next level"&lt;/em&gt; (&lt;a href="https://www.oreilly.com/library/view/javascript-the-definitive/9781491952016/" rel="noopener noreferrer"&gt;O’Reilly&lt;/a&gt;). This applies to  senior developers as well, as we had senior developer candidates that, to our surprise, lacked the basic and fundamental JavaScript knowledge.&lt;/p&gt;

&lt;p&gt;That would be my 4th advice:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Read a book to master the subject&lt;/strong&gt;&lt;br&gt;
It's never too late to strengthen your fundamental knowledge. Don't feel uncomfortable going back to basics. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The end
&lt;/h2&gt;

&lt;p&gt;Don't get me wrong. I'm no bookworm and I don't have a long list of books I want to read. I'm also not a routine person so my reading habits often change. With fields such as IT that constantly change, learning is an endless story in a life lasting sprint. I still get my tech weekly digests, but as my career changed direction a bit I started reading management books, going once more through most of the steps I went when I started as a developer.&lt;/p&gt;

&lt;p&gt;My 5th and final advice would be:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Find the time to read&lt;/strong&gt;&lt;br&gt;
Change your priorities, change your routine.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;At &lt;a href="http://cognism.com/" rel="noopener noreferrer"&gt;Cognism&lt;/a&gt;, we are enabled and encouraged to improve and educate ourselves by reading and taking courses. My first try at better reading habits was booking reading slots during the work week in the calendar. But it was quite hard to come into the office, take a book out and start reading there. Once I'm in the office I enter the &lt;em&gt;office mode&lt;/em&gt;. Usually one or two persons are already on Slack waiting for me, emails waiting to be replied to, meetings to attend etc. What I started doing at one point was instead of going directly to the office, I would spend 30-45 minutes in the building's coffee bar reading and would come into the office a bit later. &lt;br&gt;
Finding time to read at home is hard as well. Especially with 3 small children running around. For a while I did manage to squeeze in a slot. Once we put our 3 children to bed, instead of turning on Netflix immediately, I would spend 30-40 minutes reading, and then we would proceed to the newest must-watch series. Does not seem much, but falls nicely into the daily routine. &lt;br&gt;
In the end it is not about having time, we all have 24 hours in our day, but it's about the priorities and on how you want to spend your time.&lt;br&gt;
Experiment with different times and see what suits you the most and try to stick with it. If you have any suggestions or want to share any of you struggles please do post them in the discussion below!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;The race for excellence has no finish line.&lt;/em&gt; (a wise internet person)&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Feel free to connect 👋&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/petar-garzina/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; | &lt;a href="https://twitter.com/pgarzina" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | &lt;a href="https://www.instagram.com/pgarzina/" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>computerscience</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Cursors, shortcuts and clipboards; increasing your productivity</title>
      <dc:creator>Petar Garžina</dc:creator>
      <pubDate>Wed, 21 Dec 2022 12:54:58 +0000</pubDate>
      <link>https://dev.to/pgarzina/cursors-shortcuts-and-clipboards-increasing-your-productivity-39mi</link>
      <guid>https://dev.to/pgarzina/cursors-shortcuts-and-clipboards-increasing-your-productivity-39mi</guid>
      <description>&lt;p&gt;Save time. Increase productivity. Here are several small things that will make you a bit faster, and your work a bit more enjoyable. I hope you'll pick up at least one or two things. You can go wild and use all of these. It's a good start if you want to progress into a real power user.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Notes:&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Several GIFs ahead. Just click on it to stop it looping.&lt;/li&gt;
&lt;li&gt;Hotkeys used are for MacOS, but if you replace ⌘ with ctrl you should be all set for Win/Linux.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Use your cursors wisely
&lt;/h2&gt;

&lt;p&gt;The same way a craftsman uses his hands as tools in the physical world, we use our mouse and keyboard as a tool in the digital world. It may not be our most important tool, but nevertheless as a tool we should be always looking to improve how we use it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Copy a single line
&lt;/h3&gt;

&lt;p&gt;Everyone knows how to copy a line right? (⌘ + C)&lt;/p&gt;

&lt;p&gt;Some might not know that you don't need to go through the pain of highlighting a line in order to copy it. Put the cursor anywhere on the line, hit the shortcut and the line will get copied.&lt;/p&gt;

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

&lt;p&gt;People struggle clicking three times to highlight the line, sometimes they click the fourth time, highlighting the whole text. Or they drag the cursor along the line usually messing up the highlight or end up missing a couple of characters.&lt;/p&gt;

&lt;p&gt;Place the cursor in position and hit that shortcut!&lt;/p&gt;

&lt;h3&gt;
  
  
  Remove a single line
&lt;/h3&gt;

&lt;p&gt;The same cursor placement magic that applies when copying a line also applies when removing a line. The quickest way to remove a line is placing the cursor anywhere on that line and hitting ⌘ + X.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv8xyke3jyzq0klybr054.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv8xyke3jyzq0klybr054.gif" alt="Image description"&gt;&lt;/a&gt;&lt;br&gt;
One thing to note here is that ⌘ + X cuts the lines, it does not delete them. So it affects your clipboard, or the clipboard manager that you use. You do use a clipboard manager right?&lt;/p&gt;

&lt;p&gt;If you actually want to delete the line then you should use a different shortcut, ⌘ + shift + K. The shortcut is for VS Code, it might differ for other IDEs.&lt;/p&gt;

&lt;p&gt;Since the above shortcut is a bit harder and takes a bit more time to perform than the one for cutting, my preference is ⌘ + X.&lt;/p&gt;

&lt;h3&gt;
  
  
  Multi-cursors
&lt;/h3&gt;

&lt;p&gt;Place one cursor to edit a single line, place multiple cursors to edit multiple lines! Multi-cursors are your friends for fast simultaneous edits.&lt;/p&gt;

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

&lt;p&gt;Once you get a hang of it you'll love it as it makes coding a lot more fun. The two main shortcuts are ⌘ + D which selects the word at the cursor, or the next occurrence of the current selection, and Alt+ Click that adds secondary cursors.&lt;/p&gt;

&lt;p&gt;This was a game changer for me, and I used it on a daily basis. I seriously recommend you learn the basic shortcuts and give it a go.&lt;/p&gt;

&lt;p&gt;This is something all popular Integrated Development Environments have, &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;VS Code&lt;/a&gt;, &lt;a href="https://www.jetbrains.com/" rel="noopener noreferrer"&gt;JetBrains&lt;/a&gt; IDE's, &lt;a href="https://atom.io/" rel="noopener noreferrer"&gt;Atom&lt;/a&gt;, &lt;a href="https://www.sublimetext.com/" rel="noopener noreferrer"&gt;Sublime&lt;/a&gt; so you can definitely try it out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Clipboard manager
&lt;/h2&gt;

&lt;p&gt;Now that you know how to copy lines more easily and know how to add a bunch of cursors and copy all the lines at once, you need a better storage place for the data you copied. Instead of overwriting what you copied with each new copy, a clipboard manager enables you to store the data you copy.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Copy from the browser, switch to the IDE to paste, then go back to the browser to copy again, switch to the IDE to paste, go back to... &lt;strong&gt;no more!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Copy all the things you need from the browser, switch to your IDE and paste one by one in the desired location.&lt;br&gt;
While on Windows I used &lt;a href="https://ditto-cp.sourceforge.io/" rel="noopener noreferrer"&gt;Ditto&lt;/a&gt; as it has several cool features. On MacOS I use &lt;a href="https://tapbots.com/pastebot/" rel="noopener noreferrer"&gt;Pastebot&lt;/a&gt; which also comes with some advanced features. One of the features I use is Custom Pasteboards where I keep a permanent &lt;a href="https://loremipsum.io/" rel="noopener noreferrer"&gt;Lorem Ipsum&lt;/a&gt; paragraph which is always useful to have at hand while developing and testing. I also keep my personal Zoom link there as well as it makes setting up meetings on the fly easier. If you find yourself using something over and over again and it might fit into a persistent pasteboard, add it (don't add passwords tho)!&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigating through the codebase
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use ⌘ + P to quickly open a file.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Don't start looking for the file in the IDEs file Explorer, opening and closing different folders trying to locate it. Or even worse, using the global search to search for something you know is in that file, just to open it.  This is something I have witnessed first hand, and usually gets me agitated :)&lt;/p&gt;

&lt;p&gt;Pretty much all of the modern editors have this documented in more length. Two main actions follow.&lt;/p&gt;

&lt;h3&gt;
  
  
  Open a file
&lt;/h3&gt;

&lt;p&gt;You can open any file by its name when you type ⌘ + P (Quick Open). As you start typing the IDE will narrow down the list of files from which you can select to open. You don't have to go to the File Explorer and dig up a file.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Find a symbol or jump to a line
&lt;/h3&gt;

&lt;p&gt;Use ⌘ + P and append @ to find  a method inside the file. You can also combine ⌘ + P with @ and/or : to easily jump to methods, variables or jump to lines. I usually use it to jump to a line, especially if I see the line mentioned in the error stack trace.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Jump to definition
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Use your mouse keys.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can jump to definition with ⌘+ Click , but you cannot jump back. Once you jumped in, the only way to go back is to navigate back with ⌘+ - . At that point if you need to see the definition once more, you can just navigate forward using ⌘+ shift + -. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Jumping in several definitions consecutively and then navigating back and forth between them to better understand the data flow in yours or someone else's program is something you have to get familiar with.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The shortcuts here are quite impractical. Of course you can change the shortcuts to your liking. But the neat thing here is that you can also use your mouse to navigate. You just need a mouse with two additional keys which are usually by default bound as navigational keys. You can then use those keys to navigate between the methods in your IDE. And since jumping in requires a mouse click, it feels natural to continue to navigate using the mouse keys.&lt;/p&gt;

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

&lt;p&gt;Even if you don't want to use your mouse keys, do learn the shortcuts or change them as you like. Any of the above is better than navigating back by trying to find the file that you just jumped out of in the list of your currently opened files. The shortcut is a lifesaver here.&lt;/p&gt;

&lt;p&gt;These are only bits and pieces I picked up in my own journey that made it a bit more fun, hope it will do the same to you. They might not seem much but as the years go by they will add up. &lt;/p&gt;

</description>
      <category>productivity</category>
      <category>beginners</category>
    </item>
    <item>
      <title>5 tools to automate your development</title>
      <dc:creator>Petar Garžina</dc:creator>
      <pubDate>Fri, 27 Aug 2021 12:43:48 +0000</pubDate>
      <link>https://dev.to/pgarzina/5-tools-to-automate-your-development-3m</link>
      <guid>https://dev.to/pgarzina/5-tools-to-automate-your-development-3m</guid>
      <description>&lt;p&gt;Automating your development with Dependabot, Auto Assign, Merge Freeze, Husky and Scheduled reminders.&lt;/p&gt;

&lt;p&gt;The idea of this post is to introduce some of the tools and integrations that made our development life easier.&lt;/p&gt;

&lt;p&gt;Most of these are pretty straightforward to implement into your workflow but for the ones that have a couple of gotchas I might write an extended introductory version for that tool alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Dependabot
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Automated dependency updates&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;&lt;em&gt;Dependabot creates pull requests to keep your dependencies secure and up-to-date.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dependabot.com/" rel="noopener noreferrer"&gt;Dependabot&lt;/a&gt; is dead simple and their punchline clearly states what it does. We started using it a couple of years back, a bit before &lt;a href="https://dependabot.com/blog/hello-github/" rel="noopener noreferrer"&gt;Github acquired it&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The main reason was that, at the time our current team took over the Front End division, there were a lot of outdated dependencies which we wanted to update and wanted to keep up to date. We found Dependabot, added it to our projects, and let it do its magic ever since.&lt;/p&gt;

&lt;p&gt;Now it's natively a part of Github, so adding it is even easier than before.  You can &lt;a href="https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically" rel="noopener noreferrer"&gt;check out&lt;/a&gt; how to set up Dependabot, but in the end you'll end up with a &lt;code&gt;dependabot.yml&lt;/code&gt; in your &lt;code&gt;.github&lt;/code&gt; folder.&lt;br&gt;
Ours looks like this:&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;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
&lt;span class="na"&gt;updates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;package-ecosystem&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;npm"&lt;/span&gt; &lt;span class="c1"&gt;# See documentation for possible values&lt;/span&gt;
    &lt;span class="na"&gt;directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/"&lt;/span&gt; &lt;span class="c1"&gt;# Location of package manifests&lt;/span&gt;
    &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;daily"&lt;/span&gt;
    &lt;span class="na"&gt;open-pull-requests-limit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
    &lt;span class="na"&gt;commit-message&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
       &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;BleedingEdge"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The only thing that differs from the default settings is that we:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;chose npm as our package-ecosystem&lt;/li&gt;
&lt;li&gt;limited the number of open PRs to 2&lt;/li&gt;
&lt;li&gt;added a prefix for the default Dependabots commit message (you'll see later why)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Four years back we had 3 frontend repos, now we have around 14 active ones. Manually keeping every dependency up to date would be extremely time consuming. Dependabot helps a lot, but it still takes time to review and merge all the PR's. We usually take a day, after our weekly release, to merge Dependabots pull requests.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Writing this got me wondering if we could set the bot to open PR's only on major, minor or patch versions and indeed the feature &lt;a href="https://github.com/dependabot/dependabot-core/issues/2219" rel="noopener noreferrer"&gt;was requested in 2018&lt;/a&gt; and got released a few months ago and now you can ignore SemVer updates of your choice. Check out &lt;a href="https://github.blog/changelog/2021-05-21-dependabot-version-updates-can-now-ignore-major-minor-patch-releases/" rel="noopener noreferrer"&gt;GitHub's blog post&lt;/a&gt; for more.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Auto Assign
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Add reviewers/assignees to pull requests when pull requests are opened.&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;So you opened a pull request, you need at least two approvals and you need to add reviewers to your pull request. Every single time.&lt;/p&gt;

&lt;p&gt;Things are pretty obvious, let the bot do it. &lt;/p&gt;

&lt;p&gt;Setting up is easy, go to &lt;a href="https://probot.github.io/apps/auto-assign/" rel="noopener noreferrer"&gt;probot.github.io/apps/auto-assign&lt;/a&gt; hit the Add to Github button and don't ever worry about manually adding reviewers!&lt;br&gt;
Similar to Dependabot, you will end up with a &lt;code&gt;auto_assing.yml&lt;/code&gt; file:&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="c1"&gt;# Set to true to add reviewers to pull requests&lt;/span&gt;
&lt;span class="na"&gt;addReviewers&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;# Set to true to add assignees to pull requests&lt;/span&gt;
&lt;span class="na"&gt;addAssignees&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="c1"&gt;# A list of reviewers to be added to pull requests (GitHub user name)&lt;/span&gt;
&lt;span class="na"&gt;reviewers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;teammember1&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;teammember2&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;teammember3&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;...&lt;/span&gt;


&lt;span class="c1"&gt;# A number of reviewers added to the pull request&lt;/span&gt;
&lt;span class="c1"&gt;# Set 0 to add all the reviewers (default: 0)&lt;/span&gt;
&lt;span class="na"&gt;numberOfReviewers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;

&lt;span class="c1"&gt;# A list of keywords to be skipped the process that add reviewers if pull requests include it&lt;/span&gt;
&lt;span class="na"&gt;skipKeywords&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;BleedingEdge&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;We have nothing out of the ordinary here. We are utilizing the &lt;em&gt;skipKeywords&lt;/em&gt; option with the &lt;em&gt;BleedingEdge&lt;/em&gt; keyword that if you remember Dependabot prefixes to each of its pull requests. We handle the pull requests Dependabot opens a little bit differently and don't want to burden all the reviewers with them.&lt;/p&gt;

&lt;p&gt;Once the Pull request is opened the bot kicks in and you see it in the timeline requesting reviews:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ke3agursj98fenqcs28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4ke3agursj98fenqcs28.png" alt="Auto assign bot"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;You can also try and use the default settings Github provides for Code Review Assignments. Just go to your team page, in the top right hit Settings and you'll find the Code review assignments tab. We tried it but it didn't work out for us.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  3. Merge Freeze
&lt;/h2&gt;
&lt;h3&gt;
  
  
  &lt;em&gt;The code freeze tool to block merging and deployments&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;The reason for adding merge freeze originated from a simple question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Can you tell all the developers to stop merging since we are starting regression?&lt;/em&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We could announce it in our team's channel in hopes that everyone reads the message in time. Or we could integrate a tool that allows the QA team to issue a command on Slack that freezes/unfreezes merging to the repository. &lt;a href="https://www.mergefreeze.com/" rel="noopener noreferrer"&gt;Merge Freeze&lt;/a&gt; to the rescue.&lt;/p&gt;

&lt;p&gt;Again, setting up, nothing too complex. What we did find Merge Freeze is missing is the ability to bulk freeze. It worked well when we needed to freeze a couple of repos. But once the number of our repositories increased to over 10, manually entering the command more than 10 times... you get it.&lt;/p&gt;

&lt;p&gt;For this we used &lt;a href="https://slack.com/apps" rel="noopener noreferrer"&gt;Slack Apps&lt;/a&gt; and &lt;a href="https://aws.amazon.com/lambda/" rel="noopener noreferrer"&gt;AWS Lambda&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We created a custom Slack App for our workspace called Deployment, that has two Slash commands: &lt;code&gt;/freeze_all&lt;/code&gt; and &lt;code&gt;/unfreeze_all&lt;/code&gt;. Both commands have the Request URL set to our Lambda url, and pass the freeze value as a query parameter: &lt;code&gt;?freeze=true | false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Using it on Slack looks like this:&lt;/p&gt;

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

&lt;p&gt;The Merge Freeze tool exposes an API endpoint for each repository you add to it, which you can use to freeze or unfreeze it. That makes the Lambda rather simple, it just makes a POST request to each of the endpoints provided by MergeFreeze.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;freezeValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getFreezeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;freezeValue&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;BOOM! You need to provide a freeze value as a query param, either true or false&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;userName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getUserName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mergefreeze.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&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;Content-Type&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;application/json&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;Content-Length&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;appOneOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/api/branches/your-organization/your-repo/main/?access_token=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ACCESS_TOKEN&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;frozen=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;freezeValue&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;amp;user_name=&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;userName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;baseOptions&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="cm"&gt;/** Removed the rest of declaration to keep the preview short */&lt;/span&gt;


  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="nf"&gt;doRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;appOneOptions&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="nf"&gt;doRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;appElevenOptions&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;]);&lt;/span&gt;

  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;I'm done with all your promises!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Text that gets return to Slack that is only visible to the person entering the command&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;You have such power!!!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;doRequest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&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="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;https&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&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;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setEncoding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;responseBody&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;data&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;chunk&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;responseBody&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;chunk&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;end&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="nf"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;responseBody&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;

      &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;error&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;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
      &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;end&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="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getFreezeValue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;freezeQueryString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryStringParameters&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryStringParameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;freezeQueryString&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;queryStringParameters&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;freezeQueryString&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;freezeQueryString&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;false&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;freeze&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;freezeQueryString&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;freeze&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;getUserName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bodyQueryParams&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;URLSearchParams&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;bodyQueryParams&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user_name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Web API&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;After entering the command, MergeFreeze lists all the repos that got frozen or unfrozen and you get a confirmation message from Slack, making your work day a bit better!&lt;/p&gt;

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

&lt;p&gt;After the regression is done, everything is pushed to Production and is smoke tested, the lead QA issues the &lt;code&gt;unfreeze_all&lt;/code&gt; command and life goes on.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Husky
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Modern native Git hooks made easy&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;We use Jira as our work management tool so we have to prepend the ticket ID to our branch names and commit messages in order to utilize both the Development panel when viewing an issue and VSCodes extension GitLens:&lt;/p&gt;

&lt;p&gt;Jira ticket Development panel:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wgvumpwofinjccdlsak.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2wgvumpwofinjccdlsak.png" alt="Jira Development Panel"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means that each time you create a branch you have to remember to include the Jira issue ID, eg: task-&lt;strong&gt;ND-123&lt;/strong&gt;-add-authentication. That alone was not a big deal as it quickly became a habit. But what was a PIA was prepending it to every commit message. The 1st automation round was just setting up the git &lt;code&gt;prepare-commit-message&lt;/code&gt; hook on your local machine, but as the team grew larger we needed a better solution which Husky provided!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://typicode.github.io/husky" rel="noopener noreferrer"&gt;Husky&lt;/a&gt; in combination with &lt;a href="https://github.com/bk201-/jira-prepare-commit-msg" rel="noopener noreferrer"&gt;jira-prepare-commit-msg&lt;/a&gt; is what worked for us:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"private"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"husky"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"prepare-commit-msg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"jira-prepare-commit-msg"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"jira-prepare-commit-msg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"messagePattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"$J $M"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jiraTicketPattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"(&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;w+-&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;w+-&lt;/span&gt;&lt;span class="se"&gt;\\&lt;/span&gt;&lt;span class="s2"&gt;d+)"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"devDependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"husky"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^4.3.8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"jira-prepare-commit-msg"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"^1.5.2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The JIRA ticket ID is taken from a git branch name. Now you could just write &lt;code&gt;commit -m "Fixing a typo"&lt;/code&gt; and you would get a commit message looking like &lt;em&gt;task-ND-123-Fixing a typo&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In case you did not name your branch correctly eg: missing Jira ticket ID you would get an error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;my-application git:&lt;span class="o"&gt;(&lt;/span&gt;main&lt;span class="o"&gt;)&lt;/span&gt; ✗ git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add authentication methods"&lt;/span&gt;
husky &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; prepare-commit-msg &lt;span class="o"&gt;(&lt;/span&gt;node v14.15.0&lt;span class="o"&gt;)&lt;/span&gt;
JIRA prepare commit msg &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; start
JIRA prepare commit msg &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; Error: The JIRA ticket ID not found
JIRA prepare commit msg &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This came in nicely as everything was set up in &lt;code&gt;package.json&lt;/code&gt; and a new developer would do &lt;code&gt;npm i&lt;/code&gt; and she/he is pretty much set, no need to manually configure hooks.&lt;/p&gt;

&lt;p&gt;But the Jira Ticket ID in the commit message in combination with GitLens is what really made this super useful. &lt;/p&gt;

&lt;p&gt;GitLens with Git blame annotations:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fig9br67fr317myzh0sed.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fig9br67fr317myzh0sed.png" alt="Visual Studio Code and GitLens"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There were a lot of times where we had to, for various reasons, open up and read the Jira issue associated with the code change. Having the ticket ID at each mouse click throughout the codebase saved us a lot of time. (opening it in the browser is easy as well, just take the Jira ID and add it after &lt;em&gt;.../browse/&lt;/em&gt; + &lt;em&gt;ND-123&lt;/em&gt; e.g., &lt;a href="https://your-organization.atlassian.net/browse/ND-123" rel="noopener noreferrer"&gt;https://your-organization.atlassian.net/browse/ND-123&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;GitLens is a cool tool which I personally use on a daily basis. It helps you to visualize code authorship at a glance via Git blame annotations and code lens. You can also very easily navigate back in history to see past commits which is useful as well.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Scheduled reminders for Pull Requests
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;em&gt;Scheduled reminders help teams focus on the most important review requests&lt;/em&gt;
&lt;/h3&gt;

&lt;p&gt;This is something we added not too long ago, just a bit after we moved to Micro Frontend Architecture. One of the reasons for adding it was that the number of repositories increased from 4 to 14 so having a dedicated channel for open pull requests made sense. Prior to this we would post a link of the PR in our team's main channel, or would hope people would see it in their email. This way we moved the noise to a dedicated channel, and the devs know the team will get automatically notified.&lt;/p&gt;

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

&lt;p&gt;We get notifications on every working day each full hour from 8-16. It ignores approved pull requests (in our case when 2+ ppl approved it) and we also have ignore terms for &lt;em&gt;BleedingEdge&lt;/em&gt; so it ignores pull requests opened by Dependabot.&lt;/p&gt;

&lt;p&gt;Setting up &lt;a href="https://docs.github.com/en/organizations/organizing-members-into-teams/managing-scheduled-reminders-for-your-team" rel="noopener noreferrer"&gt;scheduled reminders&lt;/a&gt; is straightforward and you can find the github docs &lt;a href="https://docs.github.com/en/github/setting-up-and-managing-your-github-user-account/managing-your-membership-in-organizations/managing-your-scheduled-reminders" rel="noopener noreferrer"&gt;here&lt;/a&gt;. This is how it looks like once its up, in our case it posts messages in a private &lt;em&gt;frontend-pull-requests&lt;/em&gt; channel:&lt;/p&gt;

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

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

&lt;p&gt;There are a lot of improvements that we could include on top of what we have, like creating branches directly from Jira would ease up on having to remember the naming convention. Or maybe we could have chosen a merge freeze tool that has bulk freeze built in. But usually we had limited time for investigation, or it was good enough at that time, and later on we just tried to improve the process instead of replacing the tool. &lt;br&gt;
If you have any suggestions, please do post them in the discussion below! &lt;/p&gt;




&lt;p&gt;Feel free to connect 👋&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/pgarzina" rel="noopener noreferrer"&gt;Twitter&lt;/a&gt; | &lt;a href="https://www.instagram.com/pgarzina/" rel="noopener noreferrer"&gt;Instagram&lt;/a&gt; | &lt;a href="https://www.linkedin.com/in/petar-garzina/" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>github</category>
      <category>devops</category>
    </item>
    <item>
      <title>Adding ESLint to an Angular Micro Frontend architecture</title>
      <dc:creator>Petar Garžina</dc:creator>
      <pubDate>Tue, 18 May 2021 13:47:21 +0000</pubDate>
      <link>https://dev.to/pgarzina/adding-eslint-to-an-angular-micro-frontend-architecture-161g</link>
      <guid>https://dev.to/pgarzina/adding-eslint-to-an-angular-micro-frontend-architecture-161g</guid>
      <description>&lt;p&gt;Recently we moved our platform from a mono repo to a micro frontend architecture. One of the things we wanted to add was a base linter that is shared across our apps to ensure a more standardized code as both the platform and the number of micro applications expand.&lt;/p&gt;

&lt;p&gt;In this post I'll share the basic rundown of the things we had to do in order to get the linter up and running.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Transition from TSLint to ESLint
&lt;/h2&gt;

&lt;p&gt;As noted in the ng lint &lt;a href="https://angular.io/cli/lint"&gt;Angular Docs&lt;/a&gt;, &lt;a href="https://palantir.github.io/tslint/"&gt;TSLint&lt;/a&gt; is being deprecated in favor of &lt;a href="https://eslint.org/"&gt;ESLint&lt;/a&gt;. The migration is rather straightforward and boils down to these two lines:&lt;/p&gt;

&lt;p&gt;installing the schematics&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ng add @angular-eslint/schematics&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;and running the converter&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ng g @angular-eslint/schematics:convert-tslint-to-eslint&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;For a more detailed migration guide, see this article: &lt;a href="https://dev.to/gsarciotto/migrating-and-configuring-eslint-with-angular-11-3fg1"&gt;https://dev.to/gsarciotto/migrating-and-configuring-eslint-with-angular-11-3fg1&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Add Super-Linter to GitHub Actions
&lt;/h2&gt;

&lt;p&gt;Setting up &lt;a href="https://github.com/github/super-linter"&gt;Super-Linter&lt;/a&gt; was super easy, since we already had a workflows &lt;code&gt;test-pull-req.yml&lt;/code&gt; file that tests our build on each pull request. Adding the linter was merely adding another step to the process.&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;Test And Lint Pull Request&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;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;main&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;build&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="nn"&gt;...&lt;/span&gt;
      &lt;span class="pi"&gt;-&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;Lint Code Base&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;github/super-linter@v3&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;NODE_ENV&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;production&lt;/span&gt;
          &lt;span class="na"&gt;VALIDATE_ALL_CODEBASE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;false&lt;/span&gt;
          &lt;span class="na"&gt;DEFAULT_BRANCH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&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;LINTER_RULES_PATH&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/&lt;/span&gt;
          &lt;span class="na"&gt;TYPESCRIPT_ES_CONFIG_FILE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.eslintrc.js&lt;/span&gt;
          &lt;span class="na"&gt;VALIDATE_TYPESCRIPT_ES&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Super-Linter &lt;a href="https://github.com/github/super-linter"&gt;docs&lt;/a&gt; are pretty self explanatory, the only additional thing we added here is the &lt;code&gt;NODE_ENV&lt;/code&gt; variable, that will be used a bit later. The &lt;code&gt;VALIDATE_ALL_CODEBASE&lt;/code&gt; variable came in nicely as the linter lints only files changed, so it makes adding new linter rules a bit more easier.&lt;/p&gt;

&lt;p&gt;At this point you are good to go, you have migrated to the new ESLint and your files are being linted on each Pull Request. Tap yourself on the back!&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Share and extend the base lint rules
&lt;/h2&gt;

&lt;p&gt;Since we have around 10 applications, adding or changing a rule requires us to change it in each of the 10 applications; ain't nobody got time for that!&lt;/p&gt;

&lt;p&gt;When we switched to the micro frontend platform we started utilizing our own Angular library for some of the configs, components, pipes and services that we use around the platform. We also keep a part of our &lt;a href="https://tailwindcss.com/"&gt;Tailwind&lt;/a&gt;(❤) config in our libraries &lt;code&gt;assets&lt;/code&gt; folder, so that was the obvious place to put our base lint config as well.&lt;/p&gt;

&lt;p&gt;One thing to note here is, to make your library include the &lt;code&gt;assets&lt;/code&gt; folder in the final &lt;code&gt;dist&lt;/code&gt; you have to explicitly tell it to.&lt;/p&gt;

&lt;p&gt;This happens in the libraries &lt;code&gt;ng-package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dest"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../../dist/app-library"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"assets"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"./assets"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lib"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"entryFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/public-api.ts"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now each application's &lt;code&gt;eslintrc.js&lt;/code&gt; can reference and extend the &lt;code&gt;base-eslint.js&lt;/code&gt; using the &lt;code&gt;extends&lt;/code&gt; property&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;root&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="na"&gt;extends&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;./node_modules/@cognism/app-library/assets/configs/linter/base-eslint.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
 &lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  4. Add application specific rules
&lt;/h2&gt;

&lt;p&gt;This is how our most basic &lt;code&gt;eslintrc.js&lt;/code&gt; config looks like in one of our micro applications.&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;root&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="na"&gt;extends&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;./node_modules/@cognism/app-library/assets/configs/linter/base-eslint.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
 &lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="na"&gt;overrides&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;files&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;*.ts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
     &lt;span class="na"&gt;rules&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;@angular-eslint/component-selector&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;error&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;element&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app-nav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;kebab-case&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;@angular-eslint/directive-selector&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;error&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;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;attribute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;appNav&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;camelCase&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="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;As you can see, first we extend our &lt;code&gt;base-eslint.js&lt;/code&gt; rules and then we override it with our application specific rules. In this case we just want to have application specific prefixes for both components and directives.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Add environment dependent rules
&lt;/h2&gt;

&lt;p&gt;The idea here was to enable different rule behaviors depending on the environment. For example the &lt;code&gt;console.log&lt;/code&gt;. We don't want the log statement committed to the main branch, but we also don't want to give out errors to developers while writing logs in their local environment.&lt;/p&gt;

&lt;p&gt;The easiest way to do it was by simply using a ternary operator inside the lint file. Note that your config file must be in &lt;code&gt;.js&lt;/code&gt; format and not in the default &lt;code&gt;.json&lt;/code&gt; format to be able to do this.&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="p"&gt;...&lt;/span&gt;
      &lt;span class="na"&gt;rules&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;@typescript-eslint/naming-convention&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;error&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;selector&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;enumMember&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;format&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;UPPER_CASE&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;@angular-eslint/no-empty-lifecycle-method&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;off&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;no-console&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NODE_ENV&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;production&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;error&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;warn&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;As you can see, this is where the &lt;code&gt;NODE_ENV&lt;/code&gt; kicks in which we defined in our GitHub Actions &lt;code&gt;test-pull-req.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;We did implement different environments this way, but are also aware that it might get messy with a lot of ternaries in different rules. If that comes to be the case, we ll just start using two files, eg. &lt;code&gt;eslintrc.js&lt;/code&gt; and &lt;code&gt;prod-eslintrc.js&lt;/code&gt; and the &lt;code&gt;test-pull-req.yml&lt;/code&gt; file will always point to &lt;code&gt;prod-eslintrc.js&lt;/code&gt; while in development we'll use &lt;code&gt;eslintrc.js&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. There you have it!
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;We used single-spa &lt;a href="https://single-spa.js.org/"&gt;https://single-spa.js.org/&lt;/a&gt; to move our monolith to the front-end microservices world.&lt;/li&gt;
&lt;li&gt;The Angular version used was v11.&lt;/li&gt;
&lt;li&gt;If you need any additional info feel free to reach out.&lt;/li&gt;
&lt;li&gt;Any comments and improvements are welcome.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Feel free to connect 👋&lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/pgarzina"&gt;Twitter&lt;/a&gt; | &lt;a href="https://www.instagram.com/pgarzina/"&gt;Instagram&lt;/a&gt; | &lt;a href="https://www.linkedin.com/in/petar-garzina/"&gt;LinkedIn&lt;/a&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>eslint</category>
      <category>microfrontend</category>
    </item>
  </channel>
</rss>
