<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Just Enough Dev]]></title><description><![CDATA[What I wish I knew sooner.
Sharing my knowledge, tools, strategies and opportunities to accelerate your growth as a software engineer!]]></description><link>https://newsletter.justenough.dev</link><image><url>https://substackcdn.com/image/fetch/$s_!0vv-!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd46fb83c-c2fa-446f-9910-341fac4da36f_512x512.png</url><title>Just Enough Dev</title><link>https://newsletter.justenough.dev</link></image><generator>Substack</generator><lastBuildDate>Wed, 06 May 2026 22:47:37 GMT</lastBuildDate><atom:link href="https://newsletter.justenough.dev/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Abdu Taviq]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[abduvik@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[abduvik@substack.com]]></itunes:email><itunes:name><![CDATA[Abdu Taviq]]></itunes:name></itunes:owner><itunes:author><![CDATA[Abdu Taviq]]></itunes:author><googleplay:owner><![CDATA[abduvik@substack.com]]></googleplay:owner><googleplay:email><![CDATA[abduvik@substack.com]]></googleplay:email><googleplay:author><![CDATA[Abdu Taviq]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Issue #18: Form Encoding, OSINT, Staging Environment Hacked]]></title><description><![CDATA[What I wish I knew sooner. Sharing my knowledge, tools, strategies and opportunities to accelerate your growth as a software engineer!]]></description><link>https://newsletter.justenough.dev/p/issue-18-form-encoding-osint-staging</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-18-form-encoding-osint-staging</guid><pubDate>Tue, 22 Apr 2025 07:00:32 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/31f3cd2f-ca89-4409-94c0-1c6511a05744_905x552.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Sabah El-Khier &#128075;</p><p>or &#8220;Good Morning&#8221; in Arabic &#128513; I hope you are still keeping it together with everything going on in this world and apparently we are heading to a new world order mixed with wars, a climate crisis and a financial crisis but we have to do what we can do, and do it together.</p><p>At least you weren&#8217;t hacked like what happened to me on a staging environment that I sat up to late find out someone is using it for a phishing attack. More on this story later in the newsletter &#128064;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!APy8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!APy8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg 424w, https://substackcdn.com/image/fetch/$s_!APy8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg 848w, https://substackcdn.com/image/fetch/$s_!APy8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!APy8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!APy8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg" width="717" height="348" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:348,&quot;width&quot;:717,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:91014,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://newsletter.justenough.dev/i/161423160?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!APy8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg 424w, https://substackcdn.com/image/fetch/$s_!APy8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg 848w, https://substackcdn.com/image/fetch/$s_!APy8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!APy8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffc4ec436-0072-45b1-a7e1-842c2b3fbb7c_717x348.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h4>In This Issue</h4><ul><li><p><strong>News &amp; Articles:</strong> Rheinmetall data breach, 4chan got hacked, Japanese Web design, 70+ Tech jobboards.</p></li><li><p><strong>Poll:</strong> Were you laid off recently?</p></li><li><p><strong>Weekly Summary:</strong></p><ul><li><p>Form Submission Encoding</p></li><li><p>Open-Source Intelligence (OSINT)</p></li><li><p>How A Hacker Used My Staging Environment for Phishing</p></li></ul></li><li><p><strong>Weekly Videos:</strong></p><ul><li><p>Reality of Cybersecurity</p></li><li><p>Design Better Than 99% of UI Designers</p></li></ul></li></ul><div><hr></div><h4>News &amp; Articles</h4><ul><li><p><a href="https://x.com/_venarix_/status/1908171849021698312">German Weapon Manufacturer Rheinmetall got compromised</a></p></li><li><p><a href="https://www.404media.co/4chan-is-down-following-what-looks-to-be-a-major-hack-spurred-by-meme-war/">4chan got hacked</a></p></li><li><p><a href="https://medium.com/@mirijam.missbichler/why-japanese-websites-look-so-different-2c7273e8be1e">Why Japanese Websites Look So Different</a></p></li><li><p><a href="https://sabrinas.space/">The peculiar case of Japanese web design</a></p></li><li><p><a href="https://medium.com/@traversymedia/70-job-find-websites-for-developers-other-tech-professionals-34cdb45518be">70+ Job Find Websites For Developers &amp; Other Tech Professionals</a></p></li></ul><div><hr></div><h4>Poll</h4><div class="poll-embed" data-attrs="{&quot;id&quot;:306765}" data-component-name="PollToDOM"></div><p></p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>Form Submission Encoding</h3><p>Form submission encoding refers to the process of formatting and encoding form data before it is sent to the processing agent (such as a server). The encoding method depends on the content type specified in the form's enctype attribute.</p><p>There are two main types of commonly used encoding:</p><ul><li><p><code>application/x-www-form-urlencoded</code></p><ul><li><p>Simple format and it&#8217;s similar to what you see in the query parameters</p></li><li><p>It can be sent in get or post</p></li><li><p>Consists of pairs of keys and values separated by the &amp; symbol</p></li><li><p>Can&#8217;t be used to send files</p></li></ul></li><li><p><code>multipart/form-data</code></p><ul><li><p>More complex and covers all types of data that needs to be sent</p></li><li><p>Can be used to send files</p></li><li><p>The encoding separate between different values with a boundary</p></li><li><p>It can be used to upload multiple files using a Content-Type multipart/mixed and creates a separate boundary for it</p></li></ul></li></ul><p>Read more:</p><ul><li><p><a href="https://www.w3.org/TR/html401/interact/forms.html#h-17.13">W3 Official Documentation on Form submission</a></p></li></ul><div><hr></div><h3>Open-Source Intelligence (OSINT)</h3><p>Open-source intelligence (OSINT) is the process of gathering and analyzing publicly available information to answer specific questions mostly about a person, organization, or event. It is widely used in various fields, including cybersecurity, law enforcement, journalism, and business intelligence.</p><p>Key points about OSINT:</p><ul><li><p>Sources: News articles, social media, government records, company websites, images, videos, web archive, wikipedia, news, ...etc.</p></li><li><p>Methods: Searching, cross-referencing, analyzing, and drawing conclusions, ...etc.</p></li><li><p>Uses: Security investigations, market research, competitive analysis, due diligence, ...etc.</p></li><li><p>Benefits: Cost-effective, legal, and readily available information.</p></li><li><p>Ethics: Respect copyright, privacy, and avoid spreading misinformation.</p></li></ul><p>Read more:</p><ul><li><p><a href="https://osintframework.com/">OSINT Frameworkopen in new window</a></p></li><li><p><a href="https://www.youtube.com/watch?v=nd5W82KN9B8">OSINT: How to Find Information about ANYONE!</a></p></li></ul><div><hr></div><h3>How A Hacker Used My Staging Environment for Phishing</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!DkCY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!DkCY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp 424w, https://substackcdn.com/image/fetch/$s_!DkCY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp 848w, https://substackcdn.com/image/fetch/$s_!DkCY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp 1272w, https://substackcdn.com/image/fetch/$s_!DkCY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!DkCY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp" width="720" height="390" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:390,&quot;width&quot;:720,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13768,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:&quot;https://newsletter.justenough.dev/i/161423160?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!DkCY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp 424w, https://substackcdn.com/image/fetch/$s_!DkCY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp 848w, https://substackcdn.com/image/fetch/$s_!DkCY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp 1272w, https://substackcdn.com/image/fetch/$s_!DkCY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe9e06dd5-d83b-4df6-9372-9e2c13bf0731_720x390.webp 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>It&#8217;s never expected when you become a victim of a hacking attack but it all happen all of a sudden. I can say I have seen some hacks in my career and found a way to stop them.</p><p>But this one was very interesting!</p><p>Not because it was brilliant or something but because the hacker found my staging server which has a very weird long name including random numbers like this one: <em>&#8220;http://editor-1733357790&#8230;.wpmt.test/&#8221;</em></p><p>You can read the article on my blog for the full story and learnings. The article is behind a paywall but <a href="https://blog.abdu.dev/how-a-hacker-used-my-staging-environment-for-phishing-839daf6dd05c?sk=cdd18c34f9d09cd2e90551a1fa57cbbc">you can read it for free from here</a> &#128521;</p><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/p/issue-18-form-encoding-osint-staging?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption"><strong>Don&#8217;t keep it to yourself! Share it with someone who&#8217;d appreciate it too. Let&#8217;s spread the knowledge &#129489;&#8205;&#128187;</strong></p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/p/issue-18-form-encoding-osint-staging?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://newsletter.justenough.dev/p/issue-18-form-encoding-osint-staging?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><h4>Videos of the Week</h4><h3>Reality of Cybersecurity</h3><div id="youtube2-LGpNYQrD74I" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;LGpNYQrD74I&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/LGpNYQrD74I?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h3>Design Better Than 99% of UI Designers</h3><div id="youtube2-PGQnGEH7c-E" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;PGQnGEH7c-E&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/PGQnGEH7c-E?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><strong>Did you enjoy reading? Subscribe to receive all my future posts &#9993;&#65039;</strong></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Issue #17: Diffie-Hellman, Github SSH Accounts, UR(L/I/N)]]></title><description><![CDATA[Tech compensation trends, 23andMe DNA data sale, Lieferando layoffs, Zalando court ruling & EU Open Source Catalog. Plus: Diffie-Hellman, GitHub SSH, URL vs URI.]]></description><link>https://newsletter.justenough.dev/p/issue-17</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-17</guid><pubDate>Tue, 01 Apr 2025 14:31:38 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/31c64ffe-3f0f-4ac9-8ef3-56141286c98d_905x552.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey Hey &#128075;</p><p>What a week, huh? Too many things happening both personally and around the world, while at the same time trying to figure out German healthcare system and how it will fit into my upcoming freelancing journey.</p><p>Turns out, German healthcare system is tooooo expensive and costs a lot of money. There are many horror stories especially from migrants about how inadequate the service can be. But this story is for another day.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fKIv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fKIv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg 424w, https://substackcdn.com/image/fetch/$s_!fKIv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg 848w, https://substackcdn.com/image/fetch/$s_!fKIv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!fKIv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fKIv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg" width="800" height="600" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:600,&quot;width&quot;:800,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:63042,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:&quot;https://newsletter.abdu.dev/i/160338852?img=https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg&quot;,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!fKIv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg 424w, https://substackcdn.com/image/fetch/$s_!fKIv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg 848w, https://substackcdn.com/image/fetch/$s_!fKIv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!fKIv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F882e41ce-f927-420c-9d77-7f1e0549ed3e_800x600.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h4>In This Issue</h4><ul><li><p><strong>News &amp; Articles:</strong> Tech Compensation, 23andMe Bankruptcy, Lieferando Layoffs, Zalando&#8217;s scandal, EU Open Source Catalogue</p></li><li><p><strong>Poll:</strong> Interested into Self-employment?</p></li><li><p><strong>Weekly Summary:</strong></p><ul><li><p>Diffie-Hellman Key Exchange</p></li><li><p>Multiple Github SSH Accounts</p></li><li><p>URL vs URI vs URN</p></li></ul></li><li><p><strong>Weekly Videos</strong></p><ul><li><p>How to Start a SOLO Agency Step-By-Step</p></li><li><p>World's shortest UI/UX design course</p></li></ul></li></ul><div><hr></div><h4>News &amp; Articles</h4><ul><li><p><a href="https://newsletter.pragmaticengineer.com/p/trimodal">Trimodal Nature of Tech Compensation in the US, UK and India</a></p></li><li><p><a href="https://www.404media.co/dna-of-15-million-people-for-sale-in-23andme-bankruptcy/">DNA of 15 Million People for Sale in 23andMe Bankruptcy</a></p></li><li><p><a href="https://www.rbb24.de/wirtschaft/beitrag/2025/03/lieferando-outsourcing-berlin-spandau-lieferdienst-fahrer.html">Lieferando couriers fear massive cuts</a></p></li><li><p><a href="https://elsc.support/news/anti-palestinian-repression-in-german-companies-censorship-and-intimidation-at-zalando">Court Rules Against Zalando for Racist, Unlawful Dismissal</a></p></li><li><p><a href="https://interoperable-europe.ec.europa.eu/interoperable-europe/news/eu-open-source-solutions-catalogue-now-live">The EU Open Source Solutions Catalogue is now live</a></p></li></ul><div><hr></div><h4>Poll</h4><div class="poll-embed" data-attrs="{&quot;id&quot;:296510}" data-component-name="PollToDOM"></div><p></p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3><strong>Diffie-Hellman Key Exchange</strong></h3><p>Diffie-Hellman Key Exchange is a method to securely exchange cryptographic keys over a public channel. It uses a mix of asymmetric and symmetric encryption to create a secure channel.</p><p>We have three parties: Client, Server, and Attacker.</p><p>The steps are:</p><ol><li><p>The client and server agree on two numbers: a prime number, and a base number.</p></li><li><p>The client and server generate a private key and a public key.</p></li><li><p>The client and server exchange their public keys which has the following formula: <code>public_key = (base_number ^ private_key) % prime_number</code>.</p></li><li><p>They then exchange the public keys and generate a shared secret key using the following formula: <code>shared_secret_key = (public key of the other party ^ private key) % prime_number</code>.</p></li><li><p>Doing this, mathematically, the shared secret key will be the same for both the client and server.</p></li><li><p>The client and server can now communicate securely using the shared secret key.</p></li></ol><p>Diffie-Hellman protects against Forward Secrecy, which means that if the attacker gets the private key, they can't decrypt the previous messages.</p><p>Protecting against Forward Secrecy is important because if the attacker gets the private key, they can decrypt all the previous messages. With Diffie-Hellman, the attacker can't decrypt the previous messages because the shared secret key is only used for the current session and every session has a different shared secret key.</p><p>Read more:</p><ul><li><p><a href="https://www.youtube.com/watch?v=pa4osob1XOk">Explaining the Diffie-Hellman Key Exchange</a></p></li><li><p><a href="https://www.youtube.com/watch?v=NmM9HA2MQGI">Secret Key Exchange (Diffie-Hellman) - Computerphile</a></p></li><li><p><a href="https://www.youtube.com/watch?v=Yjrfm_oRO0w">Diffie Hellman -the Mathematics bit- Computerphile</a></p></li><li><p><a href="https://www.youtube.com/watch?v=IkM3R-KDu44">Perfect Forward Secrecy</a></p></li></ul><div><hr></div><h3><strong>Multiple Github SSH Accounts</strong></h3><p>This is useful when you have multiple accounts for github or any other git repo provider on the same machine (ex: Work and Personal accounts).</p><p>The concept is that we need to:</p><ul><li><p>Generate different SSH keys for each account</p></li><li><p>Add ssh keys to <code>~/.ssh/config</code> with separate hosts</p></li><li><p>Add condition to <code>.gitconfig</code> to use certain user for a certain directory for example</p></li><li><p>We pull the repo using a specific host name (not the domain)</p></li></ul><p>Steps:</p><ol><li><p>Generate SSH keys:</p></li></ol><pre><code><code>ssh-keygen -t ed25519 -C "&lt;email_address&gt;"
</code></code></pre><ol><li><p>Add the keys to <code>~/.ssh/config</code>:</p></li></ol><pre><code><code>Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_ed25519

Host github.com-personal
    HostName github.com
    User git
    IdentityFile ~/.ssh/id_ed25519_personal
</code></code></pre><ol><li><p>Add the condition to <code>.gitconfig</code>:</p></li></ol><pre><code><code>[includeIf "gitdir:~/work/"]
  path = .gitconfig-work
</code></code></pre><p>Then create a <code>.gitconfig-work</code> file with the following content:</p><pre><code><code>[user]
  email = &lt;email_address&gt;
  name = &lt;name&gt;
[core]
    sshCommand = "ssh -i /path/to/work/ssh/file -o IdentitiesOnly=yes"
</code></code></pre><ol><li><p>Clone the repo using the specific host:</p></li></ol><pre><code><code>git clone git@github.com:repo_org/repo_name.git
</code></code></pre><p>For the personal account:</p><pre><code><code>git clone git@github.com-personal:repo_org/repo_name.git
</code></code></pre><p>and afterwards, you can use git commands normally and it will know which credentials to use.</p><div><hr></div><h3><strong>URL vs URI vs URN</strong></h3><p>This topic might be very technical but it explains the different names and what are the different parts used to find a resource on the internet.</p><p>Let's take the following:</p><pre><code><code>https://john.doe@www.example.com:123/form/questions/?tag=networking&amp;order=news#top
</code></code></pre><p>It consists of:</p><ul><li><p><code>https</code>: Scheme. This can be HTTP, HTTPS, FTP, MAILTO, IRC, FILE, etc</p></li><li><p><code>john.doe</code>: Userinfo</p></li><li><p><code>www.example.com</code>: host</p></li><li><p><code>123</code>: Port</p></li><li><p><code>john.doe@www.example.com:123</code>: Authority</p></li><li><p><code>/form/questions</code>: Path</p></li><li><p><code>?tag=networking&amp;order=news</code>: Query</p></li><li><p><code>#top</code>: fragment</p></li></ul><p>This full thing is called a Universal Resource Locator (URL). It's used to locate exactly where is the resource.</p><p>Meanwhile, Universal Resource Identifier (URI) is used to uniquely identify a resource but not necessarily how to locate it. So, URL is just a URN + Scheme (how to locate a resource)</p><p>Uniform Resource Name (URN) are names like URI but they should be unique across space and time. They are more regulated and they usually start with the prefix <code>urn:</code>.</p><p>Read more:</p><ul><li><p><a href="https://danielmiessler.com/p/difference-between-uri-url/">The Real Difference Between a URL and a URI</a></p></li><li><p><a href="https://stackoverflow.com/questions/176264/what-is-the-difference-between-a-uri-a-url-and-a-urn">What is the difference between a URI, a URL, and a URN?</a></p></li><li><p><a href="https://stackoverflow.com/questions/2135450/why-is-urn-one-of-more-popular-formats-used-to-uniquely-identify-the-resource">Why is URN one of more popular formats used to uniquely identify the resource?</a></p></li></ul><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/p/issue-17?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption"><strong>Don&#8217;t keep it to yourself! Share it with someone who&#8217;d appreciate it too. Let&#8217;s spread the knowledge &#129489;&#8205;&#128187;</strong></p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/p/issue-17?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://newsletter.justenough.dev/p/issue-17?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><h4>Videos of the Week</h4><h3>How to Start a SOLO Agency Step-By-Step</h3><div id="youtube2-g75FZ6XfL5U" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;g75FZ6XfL5U&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/g75FZ6XfL5U?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h3><strong>World's shortest UI/UX design course</strong></h3><div id="youtube2-wIuVvCuiJhU" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;wIuVvCuiJhU&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/wIuVvCuiJhU?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><strong>Did you enjoy reading? Subscribe to receive all my future posts &#9993;&#65039;</strong></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Issue #16: Circular Dependency, Evil maid attack, Chinese Century is here]]></title><description><![CDATA[I am back again with some tech summaries, tech news and some interesting videos to increase your email productivity.]]></description><link>https://newsletter.justenough.dev/p/issue-16</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-16</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Tue, 18 Mar 2025 09:01:57 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/0a9c4ae0-1225-43f8-a8d2-e267a9ba111f_905x552.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey there, sunshine &#127774;</p><p>It has been a long time since I last sent this newsletter and a lot has changed the past few months with too many layoffs in the tech sector.</p><p>I started full self-employment, back to hitting the gym again, reading a lot of books and articles, becoming more active for migrants rights and anti-racism in Germany and I passed my German B1 Telc exam then I became shocked at what&#8217;s written by German media about migrants as I started to understand them &#128563;</p><p>But it&#8217;s good to be back posting again bi-weekly summaries about interesting tech topics I have found to accelerate your growth as a software engineer!</p><p>So let&#8217;s get into it &#128640;</p><div><hr></div><h4>This week&#8217;s News</h4><ul><li><p><a href="https://www.techradar.com/pro/security/thousands-of-github-repositories-exposed-via-microsoft-copilot">Thousands of GitHub repositories exposed via Microsoft Copilot</a></p></li><li><p><a href="https://swedenherald.com/article/signals-ceo-then-were-leaving-sweden">Signal's CEO: Then We're Leaving Sweden</a></p></li><li><p><a href="https://www.gamingonlinux.com/2025/02/ea-just-open-sourced-command-conquer-red-alert-renegade-and-generals/">EA just open sourced Command &amp; Conquer, Red Alert, Renegade and Generals</a></p></li><li><p><a href="https://www.404media.co/anyone-can-push-updates-to-the-doge-gov-website-2/">Anyone Can Push Updates to the DOGE.gov Website</a></p></li><li><p><a href="https://www.404media.co/here-is-nasas-contract-with-clearview-ai-2/">Here is NASA&#8217;s Contract with Clearview AI</a></p></li></ul><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>CommonJS<em> </em>Circular Dependency</h3><p>This week I had an issue with Circular dependency. Basically I had the issue that Package A was importing Package B but Package B was also importing Package C and then importing Package D. But suddenly I found this last one was importing Package A.</p><p>So, it was like this: <strong>A</strong> -&gt; B -&gt; C -&gt; <strong>D -&gt; A</strong></p><p>Of course, Webpack was importing A into D as an empty null and causing it to fail. The reason is not Webpack but rather CommonJs&#8217;s behaviour to avoid going into infinite loops in Circular Dependencies. It defines them as empty objects first and then adds the properties later. It works like this:</p><ul><li><p>It first Loads A</p></li><li><p>It sees A requires B</p></li><li><p>It goes to import B</p></li><li><p>&#8230;.</p></li><li><p>It then finds D needs A</p></li><li><p>It sees it&#8217;s already there as an empty object</p></li><li><p>It then returns to D an empty object</p></li></ul><p>A solution would be to add the imports at the end of A so it exports first before importing it&#8217;s dependencies</p><p>Read more:</p><ul><li><p><a href="https://stackoverflow.com/questions/30378226/circular-imports-with-webpack-returning-empty-object">Circular imports with webpack returning empty object</a></p></li></ul><div><hr></div><h3>Evil maid attack</h3><p>The attack happens by gaining physical access to the device and trying to install firmware or software that can intercept the data or the encryption keys (ex: key logger). This can happen especially in hotels or at airports or when arrested by law enforcement personnel.</p><p>To protect against this attack, you will need to monitor the devices physically and there is also the use of TPM to check the integrity of the device and the firmware.</p><p>Some ways to protect against this attack:</p><ul><li><p>Using glitter nail polish to seal the screws</p></li><li><p>Using tamper-evident stickers on ports</p></li><li><p>Using a secure boot process to check the integrity of the firmware</p></li><li><p>Using <a href="https://github.com/guardianproject/haven">Haven app</a> to monitor the device using the phone sensors</p></li></ul><p>Read more:</p><ul><li><p><a href="https://en.wikipedia.org/wiki/Evil_maid_attack">Evil maid attack</a></p></li><li><p><a href="https://theinvisiblethings.blogspot.com/2009/10/evil-maid-goes-after-truecrypt.html">Evil Maid goes after TrueCrypt!</a></p></li></ul><div><hr></div><h3>S.T.A.R. Method</h3><p>The STAR method is a structured way to provide briefings, whether in job interviews, meetings or just talking with a potential client. It entails the following structure:</p><p><strong>Situation:</strong> Give context before telling anything.</p><p><strong>Task:</strong> What was the challenge.</p><p><strong>Action:</strong> What was your own contribution. It can also be multiple actions.</p><p><strong>Result:</strong> What was the outcome of each action.</p><p>Read more:</p><ul><li><p><a href="https://www.themuse.com/advice/star-interview-method">STAR Interview method</a></p></li></ul><div><hr></div><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/p/issue-16?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption"><strong>Don&#8217;t keep it to yourself! Share it with someone who&#8217;d appreciate it too. Let&#8217;s spread the knowledge &#129489;&#8205;&#128187; </strong></p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/p/issue-16?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://newsletter.justenough.dev/p/issue-16?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><div><hr></div><h4>Videos of the Week</h4><h3><strong>The Chinese Century is here</strong></h3><div id="youtube2-KR36dgHilPE" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;KR36dgHilPE&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/KR36dgHilPE?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h3><strong>10 Gmail Productivity Tips that Changed My Life!</strong></h3><div id="youtube2-3_6eRpTkBD8" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;3_6eRpTkBD8&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/3_6eRpTkBD8?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h3><strong>How Sr Devs are *really* made</strong></h3><div id="youtube2-Ioi7DPTHG6A" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;Ioi7DPTHG6A&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/Ioi7DPTHG6A?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><strong>Did you enjoy reading? Subscribe to receive all my future posts &#9993;&#65039;</strong></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Issue #15: DDoS Protection with Nginx, Docker-in-Docker and Privacy Concerns]]></title><description><![CDATA[Let's talk about how I stopped a DDoS attack on one of my client's server, then jump to a complex topic of how to use Docker-in-Docker and lastly some videos about AI and privacy]]></description><link>https://newsletter.justenough.dev/p/issue-15</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-15</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Tue, 03 Sep 2024 08:01:41 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/2f4f5fe5-3499-4a37-97e2-032559865296_905x552.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Salam &#128075;</p><p>I have been busy the past week to plan for the revival of my YouTube Channel again with new content and new plans. So stay tuned &#128521;</p><p>I am sure some of you have read something interesting this week, maybe you can send it over to me? and I will include it in the next issue &#128591;</p><p>If you also live in Germany and plan to start your own business, I am running a survey to understand the challenges that migrants face when starting a business in Germany. If you are interested, please fill out this survey:</p><p><a href="https://forms.gle/1tUp8mnSDDXR9jtt6">https://forms.gle/1tUp8mnSDDXR9jtt6</a></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!MCWw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f184343-7e69-495d-a6ec-22bd74386d3f_1632x862.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MCWw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f184343-7e69-495d-a6ec-22bd74386d3f_1632x862.png 424w, https://substackcdn.com/image/fetch/$s_!MCWw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f184343-7e69-495d-a6ec-22bd74386d3f_1632x862.png 848w, https://substackcdn.com/image/fetch/$s_!MCWw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f184343-7e69-495d-a6ec-22bd74386d3f_1632x862.png 1272w, https://substackcdn.com/image/fetch/$s_!MCWw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f184343-7e69-495d-a6ec-22bd74386d3f_1632x862.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MCWw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f184343-7e69-495d-a6ec-22bd74386d3f_1632x862.png" width="1456" height="769" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1f184343-7e69-495d-a6ec-22bd74386d3f_1632x862.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:769,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:139372,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MCWw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f184343-7e69-495d-a6ec-22bd74386d3f_1632x862.png 424w, https://substackcdn.com/image/fetch/$s_!MCWw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f184343-7e69-495d-a6ec-22bd74386d3f_1632x862.png 848w, https://substackcdn.com/image/fetch/$s_!MCWw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f184343-7e69-495d-a6ec-22bd74386d3f_1632x862.png 1272w, https://substackcdn.com/image/fetch/$s_!MCWw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1f184343-7e69-495d-a6ec-22bd74386d3f_1632x862.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><h4>This week&#8217;s News</h4><p>Let&#8217;s try a section about some interesting tech news</p><ul><li><p><a href="https://www.reuters.com/world/europe/telegram-messaging-app-ceo-pavel-durov-arrested-france-tf1-tv-says-2024-08-24/">Telegram messaging app CEO Durov arrested in France</a></p></li><li><p><a href="https://www.aljazeera.com/economy/2024/8/31/a-tech-revolution-in-rural-india-training-poor-women-in-stem">A tech revolution in rural India: Training poor women in STEM</a></p></li><li><p><a href="https://www.amnesty.org/en/latest/news/2024/08/uk-big-tech-platforms-play-an-active-role-in-fuelling-racist-violence/">UK: Big Tech platforms play an active role in fuelling racist violence</a></p></li><li><p><a href="https://www.infomigrants.net/en/post/58508/skilled-professionals-leaving-germany-for-other-english-speaking-countries">Skilled professionals leaving Germany for other English speaking countries</a></p></li><li><p><a href="https://tech.eu/2024/09/02/latvias-emerging-tech-ecosystem/">Latvia&#8217;s emerging tech ecosystem</a></p></li><li><p><a href="https://ai.meta.com/blog/meta-llama-3-1/">Meta&#8217;s Open Source LLM Model Llama 3.1 is released</a></p></li></ul><div class="poll-embed" data-attrs="{&quot;id&quot;:209191}" data-component-name="PollToDOM"></div><p></p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>Quick DDoS Protection</h3><p>One of my client's website got under a DDoS attack and I needed to act quickly. But first I needed to confirm it was a DDoS attack and not something else:</p><ul><li><p>At first, I noticed there was a spike in CPU usage on the hosting Dashboard which could indicate many things not necessarily a DDoS attack but maybe a stuck request, an infinite loop or a bug in one of WordPress plugins or even an issue with the MySQL engine.</p></li><li><p>I logged into the server an ran the command <code>ps -aux</code> to check all currently running processes and see which one consumes the highest CPU usage and it turns out it was the PHP Engine <code>php-fpm</code></p></li><li><p>I checked the logs and found out there was a massive number of requests which just confirmed it's a DDoS attack.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YfFo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b8d5e5a-0430-4229-be69-b56621b9e4d7_1028x652.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YfFo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b8d5e5a-0430-4229-be69-b56621b9e4d7_1028x652.png 424w, https://substackcdn.com/image/fetch/$s_!YfFo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b8d5e5a-0430-4229-be69-b56621b9e4d7_1028x652.png 848w, https://substackcdn.com/image/fetch/$s_!YfFo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b8d5e5a-0430-4229-be69-b56621b9e4d7_1028x652.png 1272w, https://substackcdn.com/image/fetch/$s_!YfFo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b8d5e5a-0430-4229-be69-b56621b9e4d7_1028x652.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YfFo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b8d5e5a-0430-4229-be69-b56621b9e4d7_1028x652.png" width="1028" height="652" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4b8d5e5a-0430-4229-be69-b56621b9e4d7_1028x652.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:652,&quot;width&quot;:1028,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:64495,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!YfFo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b8d5e5a-0430-4229-be69-b56621b9e4d7_1028x652.png 424w, https://substackcdn.com/image/fetch/$s_!YfFo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b8d5e5a-0430-4229-be69-b56621b9e4d7_1028x652.png 848w, https://substackcdn.com/image/fetch/$s_!YfFo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b8d5e5a-0430-4229-be69-b56621b9e4d7_1028x652.png 1272w, https://substackcdn.com/image/fetch/$s_!YfFo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b8d5e5a-0430-4229-be69-b56621b9e4d7_1028x652.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>That's where it was confirmed it was a DDoS attack and needed to stop it in few easy steps:</p><ul><li><p>First, I updated Nginx configs with a directive to limit the number of open connections per ip to only 10 connections</p></li></ul><pre><code><code>limit_conn_zone $binary_remote_addr zone=addr:10m;

server {
    limit_conn addr 10;
}
</code></code></pre><ul><li><p>I then added a deny directive to the problematic IP address</p></li></ul><pre><code><code>http {
    deny 94.158.245.100
}
</code></code></pre><p>Voil&#224;! the CPU usage just dropped to almost normal usage thanks to Nginx's high throughput to just deny a high amount of requests easily. Of course a better option is to use CloudFlare but when under attack, one must act quickly to keep the website afloat compared to just shutting down the server!</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lRi3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa1072e-c28a-45f0-8fdc-452c4a42be1b_2380x632.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lRi3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa1072e-c28a-45f0-8fdc-452c4a42be1b_2380x632.png 424w, https://substackcdn.com/image/fetch/$s_!lRi3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa1072e-c28a-45f0-8fdc-452c4a42be1b_2380x632.png 848w, https://substackcdn.com/image/fetch/$s_!lRi3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa1072e-c28a-45f0-8fdc-452c4a42be1b_2380x632.png 1272w, https://substackcdn.com/image/fetch/$s_!lRi3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa1072e-c28a-45f0-8fdc-452c4a42be1b_2380x632.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lRi3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa1072e-c28a-45f0-8fdc-452c4a42be1b_2380x632.png" width="1456" height="387" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aaa1072e-c28a-45f0-8fdc-452c4a42be1b_2380x632.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:387,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:19518,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lRi3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa1072e-c28a-45f0-8fdc-452c4a42be1b_2380x632.png 424w, https://substackcdn.com/image/fetch/$s_!lRi3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa1072e-c28a-45f0-8fdc-452c4a42be1b_2380x632.png 848w, https://substackcdn.com/image/fetch/$s_!lRi3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa1072e-c28a-45f0-8fdc-452c4a42be1b_2380x632.png 1272w, https://substackcdn.com/image/fetch/$s_!lRi3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Faaa1072e-c28a-45f0-8fdc-452c4a42be1b_2380x632.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Read more:</p><ul><li><p><a href="https://www.cloudflare.com/learning/ddos/how-to-prevent-ddos-attacks/">How to prevent DDoS Attacks</a></p></li><li><p><a href="https://www.nginx.com/blog/mitigating-ddos-attacks-with-nginx-and-nginx-plus/">Mitigating DDoS Attacks with NGINX and NGINX Plus</a></p></li><li><p><a href="https://www.solo.io/topics/nginx/nginx-rate-limiting/">NGINX rate limiting</a></p></li></ul><div><hr></div><h3>Using Docker-in-Docker</h3><p>Using Docker-in-Docker or DinD is useful for docker development or when you want to have different isolated environments for a complex application like CI for example. Though I needed to use this approach to run a WordPress Multi-tenant architecture and it worked nicely.</p><p>There are two ways to run a DinD:</p><ul><li><p>Run a Docker container inside another Docker container and it will have its own Docker daemon and spawned containers</p></li><li><p>Run a Docker container and share the host Docker socket with the container so that it runs containers on the host directly</p></li></ul><p>I needed to use the second approach. The idea is to share the host socket <code>/var/run/docker.sock:/var/run/docker.sock</code> with the Docker container.</p><p>So an example command will be like this</p><pre><code><code>docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker:26-cli docker run nginx
</code></code></pre><p>This will run a nginx container from a docker container all shared on the same docker host</p><p>Read more:</p><ul><li><p><a href="https://jpetazzo.github.io/2015/09/03/do-not-use-docker-in-docker-for-ci/">Using Docker-in-Docker for your CI or testing environment? Think twice</a></p></li></ul><div><hr></div><h4>Videos of the Week</h4><h3>Our Privacy Is In Serious Danger By The Government Right Now...</h3><div id="youtube2-SW8V_pZxmq4" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;SW8V_pZxmq4&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/SW8V_pZxmq4?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h3>Is Google Training AI on YouTube Videos?</h3><div id="youtube2-JiMXb2NkAxQ" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;JiMXb2NkAxQ&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/JiMXb2NkAxQ?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><strong>Did you enjoy reading? Subscribe to receive all my future posts &#9993;&#65039;</strong></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div>]]></content:encoded></item><item><title><![CDATA[Issue #14: UUID, SearXNG and Raspberry Pi]]></title><description><![CDATA[We will discuss UUID and their 5 versions and what are the difference between them and then talk about the privacy-first meta-search engine SearXNG and then some interesting videos]]></description><link>https://newsletter.justenough.dev/p/issue-14</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-14</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Tue, 20 Aug 2024 08:01:21 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/769c9df1-3721-4446-9c9f-9fb3a45d5fe9_2274x1452.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>&#161;Hola!</p><p>You might have noticed that the newsletter is now under a new domain &#8220;<a href="https://justenough.dev">justenough.dev</a>&#8220;. That&#8217;s because I am launching my knowledge base into a website instead of keeping it private &#128640;</p><p>You can now visit it here and check out content for courses and backlog for this newsletter. Soon I will open also the source code for everyone to contribute &#128104;&#8205;&#128187;</p><p>Let&#8217;s strengthen our Collective Knowledge &#128170;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uinV!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2ec643-552c-4ae2-977a-59cb4117390d_3050x1872.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uinV!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2ec643-552c-4ae2-977a-59cb4117390d_3050x1872.png 424w, https://substackcdn.com/image/fetch/$s_!uinV!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2ec643-552c-4ae2-977a-59cb4117390d_3050x1872.png 848w, https://substackcdn.com/image/fetch/$s_!uinV!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2ec643-552c-4ae2-977a-59cb4117390d_3050x1872.png 1272w, https://substackcdn.com/image/fetch/$s_!uinV!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2ec643-552c-4ae2-977a-59cb4117390d_3050x1872.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uinV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2ec643-552c-4ae2-977a-59cb4117390d_3050x1872.png" width="1456" height="894" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9f2ec643-552c-4ae2-977a-59cb4117390d_3050x1872.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:894,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:347158,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uinV!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2ec643-552c-4ae2-977a-59cb4117390d_3050x1872.png 424w, https://substackcdn.com/image/fetch/$s_!uinV!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2ec643-552c-4ae2-977a-59cb4117390d_3050x1872.png 848w, https://substackcdn.com/image/fetch/$s_!uinV!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2ec643-552c-4ae2-977a-59cb4117390d_3050x1872.png 1272w, https://substackcdn.com/image/fetch/$s_!uinV!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9f2ec643-552c-4ae2-977a-59cb4117390d_3050x1872.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Check it out here: <a href="https://justenough.dev/">https://justenough.dev/</a></p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>UUID</h3><p>It is a 128-bit identifier standardized by the Open Software Foundation (OSF) to create unique identifiers for digital objects. UUIDs are commonly used in various information systems and are particularly useful in distributed systems where unique identifiers are needed without central coordination.</p><p>UUIDs are generated using algorithms designed to ensure uniqueness across space and time, even in distributed systems where multiple UUIDs might be generated concurrently. The structure of a UUID is standardized, consisting of 32 hexadecimal digits displayed in five groups separated by hyphens, like this: 8-4-4-4-12, where each digit represents four bits.</p><p>There are several versions of UUIDs, each generated using different algorithms, and they have different properties and intended uses:</p><ul><li><p><strong>Version 1 (UUID based on timestamp and MAC address):</strong> This version uses the current timestamp and the MAC address of the computer generating the UUID to create a unique identifier. It is primarily used in scenarios where uniqueness and time-based sorting are essential.</p></li><li><p><strong>Version 2 (DCE security version):</strong> Similar to version 1 but with modifications to include POSIX UID/GID.</p></li><li><p><strong>Version 3 (MD5 hash of a namespace and name):</strong> This version generates UUIDs based on a namespace identifier and a name. It uses the MD5 hashing algorithm to produce the UUID. This version is deterministic; given the same namespace&nbsp;and name, it will always produce the same UUID.</p></li><li><p><strong>Version 5 (SHA-1 hash of a namespace and name):</strong> Similar to version 3 but uses the SHA-1 hashing algorithm instead&nbsp;of MD5. Like version 3, it is deterministic.</p></li><li><p><strong>Version 4 (Randomly generated UUID:</strong> This version generates UUIDs using random or pseudo-random numbers. It provides a high probability of uniqueness. It is widely used in various applications where uniqueness is the primary concern.</p></li></ul><p>The differences between these versions primarily lie in the algorithms used for generation, the sources of randomness, and the properties of the resulting UUIDs, such as determinism and uniqueness guarantees. Each version is suitable for different use cases depending on the requirements for uniqueness, determinism, and collision resistance.</p><p>Read more:</p><ul><li><p><a href="https://en.wikipedia.org/wiki/Universally_unique_identifier">Universally unique identifier</a></p></li><li><p><a href="https://www.youtube.com/watch?v=OAOQ7U0XAi0">The effect of Random UUID on database performance</a></p></li><li><p><a href="https://www.youtube.com/watch?v=f53-Iw_5ucA">How Shopify&#8217;s engineering improved database writes by 50% with ULID</a></p></li></ul><h3><em>SearXNG</em></h3><p>Did you know that each search entry you make on Google is stored and used to build a profile about you? and that Google is using this to sell your data to advertisers or even to governments intelligence agencies?</p><p>That's why SearXNG is here to help you. SearXNG is a privacy-respecting search engine that doesn't track you. It is an open source meta-search engine that aggregates results from more than 70 search services. It is a great alternative to Google and other search engines. Also, it's much better to bypass results censorship and manipulation by these big tech companies.</p><p>You can use one of the <a href="https://searx.space/">public instances</a> or host your own instance.</p><p>Let's De-Googlify our lives!</p><p>Read more:</p><ul><li><p><a href="https://github.com/searxng/searxng">SearXNG on GitHub</a></p></li></ul><div><hr></div><h4>Videos of the Week</h4><h3><strong>Making a Game with Java with No Experience</strong></h3><div id="youtube2-iOeebAM_C5g" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;iOeebAM_C5g&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/iOeebAM_C5g?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h3><strong>Every Developer Needs a Raspberry Pi</strong></h3><div id="youtube2-Vp4glSVPT8o" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;Vp4glSVPT8o&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/Vp4glSVPT8o?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><p><em>Do you create tech content? have you read something interesting?</em></p><p><em>Send me your links and I'll attach a summary for it here and we both learn something new from each other </em>&#129303;</p><p><em>Let's increase our collective knowledge </em>&#10084;&#65039;</p><div><hr></div><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><strong>Did you enjoy reading? Subscribe to receive all my future posts &#9993;&#65039;</strong></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p></p>]]></content:encoded></item><item><title><![CDATA[Issue #13: Options vs Head, Auth with OAuth vs SAML vs Kerberos]]></title><description><![CDATA[Let's discuss the difference between HTTP API requests Options vs Head and then go to different ways used to authenticate and authorize services using OAuth vs SAML vs Kerberos]]></description><link>https://newsletter.justenough.dev/p/issue-13</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-13</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Tue, 13 Aug 2024 08:00:43 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f046e6e2-4d62-4aec-a862-98d6cb30c514_960x600.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Good morning Techiees &#129489;&#8205;&#128187;</p><p>I am finally making progress to clean up my 567 Chrome tabs &#128584; and making use of my new mini whiteboard to organize my daily todos. Very handy and only costs &#8364;5 from Woolworth &#10084;&#65039;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!VZmU!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0cddd4f-564b-49d1-ae57-afc3e8ff982b_3024x4032.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!VZmU!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0cddd4f-564b-49d1-ae57-afc3e8ff982b_3024x4032.jpeg 424w, https://substackcdn.com/image/fetch/$s_!VZmU!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0cddd4f-564b-49d1-ae57-afc3e8ff982b_3024x4032.jpeg 848w, https://substackcdn.com/image/fetch/$s_!VZmU!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0cddd4f-564b-49d1-ae57-afc3e8ff982b_3024x4032.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!VZmU!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0cddd4f-564b-49d1-ae57-afc3e8ff982b_3024x4032.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!VZmU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0cddd4f-564b-49d1-ae57-afc3e8ff982b_3024x4032.jpeg" width="372" height="495.91483516483515" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f0cddd4f-564b-49d1-ae57-afc3e8ff982b_3024x4032.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1941,&quot;width&quot;:1456,&quot;resizeWidth&quot;:372,&quot;bytes&quot;:4375584,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!VZmU!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0cddd4f-564b-49d1-ae57-afc3e8ff982b_3024x4032.jpeg 424w, https://substackcdn.com/image/fetch/$s_!VZmU!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0cddd4f-564b-49d1-ae57-afc3e8ff982b_3024x4032.jpeg 848w, https://substackcdn.com/image/fetch/$s_!VZmU!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0cddd4f-564b-49d1-ae57-afc3e8ff982b_3024x4032.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!VZmU!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff0cddd4f-564b-49d1-ae57-afc3e8ff982b_3024x4032.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Using physical todos is more satisfying than complex Notion setups &#128524;</p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>OPTIONS vs HEAD methods</h3><p>OPTIONS is used to get the allowed methods for an endpoint</p><p>HEAD is used to get meta information about the resource. They should have the same headers as the GET method response without the body. Also, this helps to check if the a cached resource should be invalided and a GET request should be initiated.</p><p>Read more:</p><ul><li><p><a href="https://stackoverflow.com/questions/6660019/restful-api-methods-head-options">RESTful API methods; HEAD &amp; OPTIONS</a></p></li></ul><h3>OAuth vs SAML vs Kerberos</h3><p>They are all ways to help authenticate and authorize users or services to another service through an identity provider.</p><p>They use different strategies and have some differences between them.</p><p><strong>OAuth:</strong></p><ul><li><p>Parties are: Client, Service Provider, and Authorization Provider</p></li><li><p>Main task: It gives a service provider access to some resource through the Authorization Provider requiring Client&#8217;s consent</p></li><li><p>OAuth allows to give scopes to these service providers to have certain access</p></li><li><p>OAuth returns an Access Token to be used by the service provider</p></li><li><p>OAuth can have an identity layer and it&#8217;s named OpenId Connect or OIDC, it returns also an Id Token which is used to identify the user</p></li><li><p>JSON-Based and uses JWTs</p></li><li><p>More modern and used by newer apps</p></li><li><p>Doesn&#8217;t require prior introduction between the Authorization Provider and Service Provider making it easy to setup</p></li></ul><p><strong>SAML:</strong></p><ul><li><p>Used mainly for Authentication but can have an authorization layer</p></li><li><p>Parties are: Client, Service Provider and Identity provider</p></li><li><p>Main task: it gives access to a client to a service provider through the identity provider</p></li><li><p>Very similar to OIDC</p></li><li><p>XML based and used by older applications and government software</p></li></ul><p><strong>Kerberos:</strong></p><ul><li><p>Used mainly for Authentication &amp; Authorization among a bunch of services with asymmetric keys (no public key) and avoid sharing keys between these many services</p></li><li><p>Parties: many services and a Key Distribution Center which includes two servers Authentication server and Ticket Granting server</p></li><li><p>Main Task: Gives access and keys to a service to communicate with another service using a session key</p></li></ul><p>Read more:</p><ul><li><p><a href="https://www.youtube.com/watch?v=t18YB3xDfXI">An Illustrated Guide to OAuth and OpenID Connect</a></p></li><li><p><a href="https://www.youtube.com/watch?v=VzRnb9u8T1A">How SAML Authentication Works</a></p></li><li><p><a href="https://www.youtube.com/watch?v=qW361k3-BtU">Taming Kerberos - Computerphile</a></p></li><li><p><a href="https://stackoverflow.com/questions/7699200/what-is-the-difference-between-openid-and-saml">What is the difference between OpenID and SAML?</a></p></li></ul><div><hr></div><h4>Videos of the Week</h4><h3><strong>Blue Light Glasses: A Waste of Money? Explained by an MD</strong></h3><div id="youtube2-h8feWf7X750" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;h8feWf7X750&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/h8feWf7X750?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h3><strong>Why Corporate America Is Obsessed With "Company Culture"</strong></h3><div id="youtube2-88SGfykwt8g" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;88SGfykwt8g&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/88SGfykwt8g?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><p><em>Do you create tech content? have you read something interesting?</em></p><p><em>Send me your links and I'll attach a summary for it here and we both learn something new from each other </em>&#129303;</p><p><em>Let's increase our collective knowledge </em>&#10084;&#65039;</p>]]></content:encoded></item><item><title><![CDATA[Issue #12: State Surveillance, Passkeys, DOMParser]]></title><description><![CDATA[This week we cover topics about state surveillance with 5-eyes, 9-eyes, 14-eyes and then speak about new way of login using Passkeys and then how to convert strings to DOM elements using DOMParser for extra security.]]></description><link>https://newsletter.justenough.dev/p/issue-12</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-12</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Tue, 06 Aug 2024 07:00:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/70f2410f-a953-4590-b3a8-8695e08191e3_960x600.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>And 3, 2, 1&#8230; I&#8217;m back &#129395;</p><p>Good morning lovely people! This is Abdu from &#8220;Software Summaries&#8221; now rebranded as &#8220;Just Enough&#8221; &#128640;</p><p>After a long absence, I am finally back to posting again and with strong content and energy to share and spread the knowledge I learned during the week with you.</p><p>The past couple of months weren&#8217;t the nicest and gave me a different prospective towards life and priority re-ordering. There is going to be changes upcoming and I would like you all to be part of it!</p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>5-eyes, 9-eyes, 14-eyes</h3><p>With the rise of Far-right and weakened democracies, privacy is a becoming a concern for many people. Awareness is the first step to protect your privacy especially if you are doing things your state might not like.</p><p>The 5-eyes, 9-eyes and 14-eyes are intelligence alliances between countries to share intelligence information between them: </p><ul><li><p><strong>5-eyes</strong>: US, UK, Canada, Australia, New Zealand </p></li><li><p><strong>9-eyes</strong>: 5-eyes + Denmark, France, Netherlands, Norway </p></li><li><p><strong>14-eyes</strong>: 9-eyes + Germany, Belgium, Italy, Spain, Sweden </p></li></ul><p>They share a wide range of intelligence information between them and they are known to spy on their citizens and other countries.</p><p>So if you are doing something that might be illegal (event activism work) in these countries, you might want to use a services (ex: Mail, Hosting, VPN, ...etc) that is not based in these countries.  </p><p>Read more:  </p><ul><li><p><a href="https://restoreprivacy.com/5-eyes-9-eyes-14-eyes/">Five Eyes, Nine Eyes, 14 Eyes (What to Avoid in 2024)</a></p></li></ul><h3>Passkeys</h3><p>Passkeys are a new way to authenticate users without the need for passwords. It's a more secure and user-friendly method that uses public-key cryptography to verify the user's identity.</p><p>The passkey is generated by the user's device and it generates a public and private key pair. The public key is sent to the server, while the private key remains on the user's device. When the user wants to authenticate, the server sends a challenge to the user's device, which is signed with the private key. The server then verifies the signature using the public key and authenticates the user.</p><p>This approach eliminates the need for passwords, which are often weak and easily compromised. It also provides a more secure and user-friendly authentication method that is resistant to phishing attacks and other security threats.</p><p>Read more:</p><ul><li><p><a href="https://www.youtube.com/watch?v=lRFeuSH9t44">FIDO Promises a Life Without Passwords</a></p></li></ul><h3>DOMParser</h3><p><code>DOMParser</code> is used for converting strings into DOM elements aka. parsing HTML string into a structured document using the <code>parseFromString</code> method and it will return a Document object which we can then use <code>adoptNode</code> to transfer a node from one document to another or use <code>cloneNode</code> to create a copy of a node within a document.</p><p>It&#8217;s similar to <code>innerHTML</code> but it&#8217;s safer as it doesn&#8217;t run the JS Code inline of the string which allows also to do transformations before <code>appendChild</code> it to the current Document.</p><pre><code>// Create an HTML string
const htmlString = "&lt;div&gt;&lt;p&gt;Hello, DOMParser!&lt;/p&gt;&lt;/div&gt;";

// Create a new DOMParser
const parser = new DOMParser();

// Use the parseFromString method to parse the HTML string
const parsedDocument = parser.parseFromString(htmlString, "text/html");

// Get the first element from the parsed document
const parsedNode = parsedDocument.body.firstChild;

// Get the parent element in the current document where the parsed node will be appended
const parentElement = document.getElementById("parent");

// Adopt the parsed node to the current document
const adoptedNode = document.adoptNode(parsedNode);

// Append the adopted node to the parent element
parentElement.appendChild(adoptedNode);</code></pre><p>Read more:</p><ul><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/DOMParser">DOMParser by mdn</a></p></li><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/adoptNode">document.adoptNode by mdn</a></p></li><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Node/cloneNode">document.cloneNode by mdn</a></p></li></ul><div><hr></div><h4>Videos of the Week</h4><h3><strong>Advanced React Course</strong></h3><div id="youtube2-5hXoIIRoWqQ" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;5hXoIIRoWqQ&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/5hXoIIRoWqQ?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h3>MacBook for $36 &#128064;</h3><div id="youtube2-LaZGFESvEJA" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;LaZGFESvEJA&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/LaZGFESvEJA?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><p><em>Do you create tech content? have you read something interesting?</em></p><p><em>Send me your links and I'll attach a summary for it here and we both learn something new from each other </em>&#129303;</p><p><em>Let's increase our collective knowledge </em>&#10084;&#65039;</p>]]></content:encoded></item><item><title><![CDATA[Issue #11: Product Development, Internet Protocol, PoC vs Prototype vs MVP]]></title><description><![CDATA[Hey Friends,]]></description><link>https://newsletter.justenough.dev/p/issue-11-product-development-internet</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-11-product-development-internet</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Tue, 11 Apr 2023 07:00:20 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/6f166e7b-8841-4ee4-8988-efcf2863c77b_960x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey Friends,</p><p>Hope you are all having a good time and getting ready for Spring &#127799;</p><p>The past two weeks were a bit relaxing but most importantly I officially started working 6hrs/day with my current employer and also got a promotion &#128640;</p><p>I am going to collect learnings from the 6hrs/day experiment and will share them with you all soon.</p><p>Wish you all a nice start to the week and enjoy a mindful time &#128591;</p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>Product Development for Developers</h3><p>During a recent Lunchclub meeting, I had the pleasure of speaking with <a href="https://www.linkedin.com/in/kbukala/">Kamil Bukala</a>, the Co-Founder and CTO of TabsFolders.com. Our conversation revolved around how developers can begin building their own products instead of solely working on projects for clients or employers. Kamil shared some valuable insights that I would like to share with you.</p><ul><li><p>One idea that Kamil presented was to repurpose an existing product, changing how it's perceived, rather than starting from scratch. This approach can be beneficial for testing out ideas before moving on to actual implementation and saving time and money in the product development process.</p></li><li><p>Another suggestion was to modify an existing source code to achieve our core concepts. This way, we can gain valuable insights and lessons early on in the product development process. This approach can also help save time and money, as we are building upon an already-existing foundation.</p></li><li><p>Hiring remote teams for building a prototype at a relatively cheaper cost. Platforms such as Upwork and Fiverr are great resources for finding remote teams to create easy prototypes. These prototypes can be used to collect feedback from potential customers.</p></li><li><p>Finally, Kamil mentioned that originality is not always necessary when attempting to solve a problem. One can find existing products and copy their ideas, targeting different markets with different demographics or geographics. This approach is similar to what Rocket Internet does, and it can be a successful strategy for building a product that meets the needs of a specific market.</p></li></ul><div class="pullquote"><p><em>Do you write tech articles? If you're interested in having your content shared with a wider audience, please send me your links and I'll attach a summary for it here.</em></p><p><em>Let's spread knowledge &#10084;&#65039;</em></p></div><h3>How the Internet works</h3><p>The internet consists of 7 network layers to communicate with each other which are:</p><ol><li><p>Physical layer: Wires and transmission that handle physical aspects of networking.</p></li><li><p>Data link layer: Reliablity transmission of data over a physical link by implementing error detection and correction mechanisms.</p></li><li><p>Network layer: Handles the routing of data between different networks by using protocols such as IP (Internet Protocol).</p></li><li><p>Transport layer: Provides end-to-end data transfer between two devices by using protocols such as TCP and UDP.</p></li><li><p>Session layer: Establishes and manages communication sessions between devices, including authentication and encryption.</p></li><li><p>Presentation layer: Responsible for data formatting, encryption, and compression.</p></li><li><p>Application layer: Provides services to applications such as email, web browsing, and file transfer. (HTTP protocol is here!)</p></li></ol><p>This video by <a href="https://www.youtube.com/@rhymu/featured">Rhymu</a> is a great intro for in-depth details of how the Internet works</p><div id="youtube2-C7CpfL1p6y0" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;C7CpfL1p6y0&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/C7CpfL1p6y0?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><h3>PoC vs Prototype vs MVP</h3><p>We usually use these terms while working as they are the same but they are quite different.</p><p><strong>PoC (Proof of Concept):</strong></p><ul><li><p>Used to check if our idea is technically feasible and possible to implement</p></li><li><p>Mainly for internal purposes and neglects UI, security, and development best practices</p></li><li><p>Example: Simple Script without any clean code or infrastructure</p></li></ul><p><strong>Prototype:</strong></p><ul><li><p>Early product sample to demonstrate a business concept before implementing it.</p></li><li><p>Good for understanding the product and user journey to find any gaps that exist</p></li><li><p>Examples: Miro Boards, Figma Designs</p></li></ul><p><strong>MVP (Minimum Viable Product)</strong></p><ul><li><p>It&#8217;s a product with the minimum features that can be launched to market</p></li><li><p>Used to validate the idea with real users and get feedback</p></li><li><p>Examples: Using No-tools apps and WordPress SaaS</p></li></ul><p>Read more:</p><ul><li><p><a href="https://www.techmagic.co/blog/poc-vs-prototype-vs-mvp/">PoC vs Prototype vs MVP: What's the difference? How to choose?</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Issue #10: Github Copilot X, Tackling Technical Debt and SELinux]]></title><description><![CDATA[Hey Friends,]]></description><link>https://newsletter.justenough.dev/p/issue-10-github-x-tackling-technical</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-10-github-x-tackling-technical</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Tue, 28 Mar 2023 07:01:05 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a1b4181b-7ba1-49bf-bbb1-ec53b94051c0_960x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey Friends,</p><p>Hope you all doing alright and having a nice start to the week &#10084;&#65039;</p><p>A bit of a long time since I published the last issue but it has been quite a ride since then :D I finally got my tax refund sorted with the Tax office, am about to finish a huge project I am working on with a client, traveled to lovely Passau, and focusing now to get in shape and finaaallly to get better in <em>Deutsch</em> &#127465;&#127466;</p><p>This week&#8217;s summary is packed with good stuff and I am sure you will like it!</p><p>Wish you all stay healthy, and fit and enjoy the upcoming good weather &#9728;&#65039;</p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>Github X</h3><p>I have been working on a huge consultation project for the past few months building a system similar to Monday.com or Personio but for nursing facilities with the help of Github Copilot which has been an arsenal on its own helping me programming in .NET which I never used before.</p><p>Now, GitHub has announced GitHub Copliot X which is the upcoming generation of Github Copilot and a few upcoming features will be:</p><ul><li><p>Integrating the same model as ChatGPT-4</p></li><li><p>Integrating Chat into VSCode which will help you understand pieces of code within the IDE</p></li><li><p>Writing unit tests</p></li><li><p>Writing Pull Requests descriptions</p></li><li><p>Integration with Frameworks docs</p></li></ul><p>Programming is never going to be the same and too much fun is coming up with this new toy :D</p><p>Read more:</p><ul><li><p><a href="https://github.com/features/preview/copilot-x">GitHub Copilot X: The AI-powered developer experience</a></p></li></ul><h3>6 Steps to Tackle Technical Debt by <a href="https://www.linkedin.com/in/seif-sayed/">Seifeldin Mahjoub</a></h3><p>Seif managed to transform a UI design system with a heavy technical debt to have repaid all of it with full interest :D</p><p>In his article, he shares tips and ideas on how to practically tackle technical debt both from engineering and management perspectives:</p><ul><li><p>Building trust among team members is crucial for tackling technical debt effectively. This involves being open and honest in communication, treating others with respect and kindness, and focusing on a shared vision.</p></li><li><p>Making technical debt visible through tools like a tech debt radar can help prioritize the most pressing issues and drive progress.</p></li><li><p>It's important to prove the need for technical debt management to stakeholders, highlighting the risks and financial impact of neglecting it.</p></li><li><p>Breaking down technical debt into smaller, manageable phases and prioritizing using frameworks like the Cyfin framework can help make the job more manageable.</p></li><li><p>Allocating dedicated time for technical improvements and making it a part of the development process can help drive progress.</p></li><li><p>Engineers should take ownership of the code and lead by example in tackling technical debt, ultimately leading to improved results for the team and the company.</p></li></ul><p>Read the full article:</p><ul><li><p><a href="https://javascript.plainenglish.io/from-technical-debt-to-technical-wealth-a-team-approach-5179f9eaeb2a">From Technical Debt to Technical Wealth: A Team Approach</a></p></li></ul><div class="pullquote"><p><em>Do you write tech articles? If you're interested in having your content shared with a wider audience, please send me your links and I'll attach a summary for it here.</em></p><p><em>Let's spread knowledge &#10084;&#65039;</em></p></div><h3>SELinux</h3><p>SELinux (Security-Enhanced Linux) is a security mechanism that provides an additional layer of protection to Linux systems. It is built into the Linux kernel and uses a Mandatory Access Control (MAC) model to enforce access controls and restrict unauthorized access to system resources. </p><p>SELinux's security mechanism is based on security contexts or labels assigned to files, processes, and other resources. The context is a combination of a user identity, role, and type that defines the level of access a resource has.</p><p>It was developed by the US National Security Agency (NSA) and is now included in most modern Linux distributions.</p><p>Some of the most important components of SELinux are:</p><ul><li><p>Security server:  responsible for enforcing security policies and access controls.</p></li><li><p>Security Policy: a set of rules and guidelines that define how the Security server should enforce access controls on the system.</p></li><li><p>SELinux Utilities: command-line tools that allow system administrators to manage and configure SELinux policies, contexts, and other related settings.</p></li><li><p>Audit system: logs security events and other system activity for troubleshooting, tracking system activity, and providing forensic analysis in case of a security breach.</p></li><li><p>Security Contexts: are assigned to files, processes, and network resources, and define their level of access.</p></li></ul><p>SELinux can be used with container technologies such as Docker and Kubernetes to enhance their security. By enabling SELinux, access controls can be restricted, preventing unauthorized access to system resources, and improving the overall security of containerized applications.</p><p>Read more:</p><ul><li><p><a href="https://www.youtube.com/watch?v=_WOKRaM-HI4">Security-Enhanced Linux for mere mortals by Thomas Cameron</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Issue #9: History API, BroadcastChannel API and Importmap]]></title><description><![CDATA[Hey Friends,]]></description><link>https://newsletter.justenough.dev/p/issue9-history-api-broadcastchannel</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue9-history-api-broadcastchannel</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Mon, 13 Feb 2023 08:01:22 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d1b82d7e-4ada-4990-bdf2-122c29ac1873_960x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey Friends,</p><p>Missed the past week&#8217;s issue as I got pretty sick but I am better now and found out that in Germany you can book a video call with a doctor which is pretty cool!</p><p>Anyways, enough rest and time to get back to discovering cool tech :D </p><p>Hope you all are healthy and having a productive week &#10084;&#65039;</p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>History API</h3><p>The History API allows to manage and manipulate the browser's history and gives the ability to update the URL displayed in the browser's address bar without reloading the page, which results in a better user experience and is a core component of routing libraries such as react-router and vue-router.</p><p>Here's an example of using the History API:</p><pre><code><code>// Using the pushState method to add a new history entry
history.pushState({
  page: 1
}, "Page 1", "/page1");

// Using the replaceState method to update the current history entry
history.replaceState({
  page: 2
}, "Page 2", "/page2");

// Listening for the popstate event to handle back/forward navigation
window.addEventListener("popstate", function(event) {
  console.log("Page:", event.state.page);
});
</code></code></pre><p>In this example, the <code>pushState</code> method is used to add a new history entry to the browser's history, with the state <code>{ page: 1 }</code>, the title "Page 1", and the URL "/page1". The <code>replaceState</code> method updates the current history entry with the state <code>{ page: 2 }</code>, the title "Page 2", and the URL "/page2".</p><p>Finally, the <code>popstate</code> event is listened for and logged to the console, which will be triggered when the user navigates back or forward through the history.</p><p>Read More:</p><ul><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/History_API">History API by mdn</a></p></li><li><p><a href="https://github.com/abduvik/just-enough-series/blob/13f8dce7edfacb4b873021fdddeadcb4dc102839/courses/react/todo/_extras/code.tsx#L6">Example code for internals in a router</a></p></li></ul><h3>BroadcastChannel API</h3><p>The BroadcastChannel API allows communication between different browsing contexts (e.g. windows, tabs, iframes) and workers in the same origin. It provides a way to broadcast a message to all listening contexts.</p><p>Here is an example of using the BroadcastChannel API to send a message from a parent window to all of its child iframes:</p><pre><code><code>// In the parent window
const channel = new BroadcastChannel('channel-name');

channel.postMessage('Hello, world!');

// In the child iframe
const channel = new BroadcastChannel('channel-name');

channel.addEventListener('message', event =&gt; {
  console.log(event.data); // 'Hello, world!'
});
</code></code></pre><p>You can also use the BroadcastChannel API to communicate between different tabs or windows. In this case, you would need to open the same channel in both tabs or windows and then use <code>postMessage</code> to send a message from one tab or window to the other.</p><pre><code><code>// In one tab or window
const channel = new BroadcastChannel('channel-name');

channel.addEventListener('message', event =&gt; {
  console.log(event.data); // 'Hello, other tab or window!'
});

// In another tab or window
const channel = new BroadcastChannel('channel-name');

channel.postMessage('Hello, other tab or window!');
</code></code></pre><p>Note that the BroadcastChannel API is not intended for communication with servers, as it only works within the same origin. If you need to communicate with a server, you can use other APIs such as WebSockets or the Fetch API.</p><p>Read more:</p><ul><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API">BroadcastChannel API by mdn</a></p></li></ul><h3>Importmap</h3><p>Import maps are a way to specify custom module resolution for JavaScript projects natively in the browser without using bundlers like Webpack or Vite. They allow you to map specific import statements to different locations, giving you more control over how your code is organized and loaded.</p><p>You can use an import map to specify that all imports starting with <code>@/components</code> should be resolved to the <code>src/components</code> folder, and all imports starting with <code>@/utils</code> should be resolved to the <code>src/utils</code> folder. Your import map file would look like this:</p><pre><code><code>{
  "imports": {
    "@/components/*": "./src/components/*",
    "@/utils/*": "./src/utils/*"
  }
}
</code></code></pre><p>In your code, you can then use the following import statements:</p><pre><code><code>import Button from '@/components/button';
import { helper } from '@/utils/helper';
</code></code></pre><p>You can also use importmap to point to external libraries or CDN.</p><pre><code><code>{
  "imports": {
    "lodash": "https://cdn.jsdelivr.net/npm/lodash@4.17.20/lodash.min.js"
  }
}
</code></code></pre><p>In your code, you can then use the following import statements:</p><pre><code><code>import _ from 'lodash';
</code></code></pre><p>It is important to note that import maps are not yet widely supported and require a browser with support for the 'import-maps' feature flag, or a tool like es-dev-server to work.</p><p>Read more:</p><ul><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap">Improtmap by mdn</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Issue #8: Trusted Events, Consumer-Driven Contracts, Native Import and Technical Debt]]></title><description><![CDATA[Hey Friends,]]></description><link>https://newsletter.justenough.dev/p/issue-8-trusted-events-consumer-driven</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-8-trusted-events-consumer-driven</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Mon, 23 Jan 2023 08:00:57 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/deeecfc5-2429-40cb-b670-b4ca8514941c_960x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey Friends,</p><p>Hope you all had a good time the past weeks and managed to start hitting those 2023 goals list. I missed issuing a newsletter the past week but for a good reason as I gave all my energy to get my free <a href="https://www.youtube.com/watch?v=5hXoIIRoWqQ">Advanced React Course published on YouTube</a>, also tried out my Play Station 5 as I finally got it :D</p><p>Wish you all a nice and productive week &#10084;&#65039;</p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>Trusted Events: The Anti-bot web solution</h3><p>Bots are automated software programs that are designed to perform tasks on the internet. They can be used for a wide range of purposes, such as scraping websites for information, posting spam comments, or simulating human behavior on social media. While bots can be useful in certain situations, they can also cause problems by overwhelming websites with traffic, spreading misinformation, or stealing sensitive information.</p><p>Javascript Web APIs support <code>isTrusted</code> which is a read-only prop and can be used in combination with <code>pageX</code> and <code>pageY</code> to enforce checking whether an event is user-generated or not. Here is a sample of this code</p><pre><code><code>function isTrustedEvent(event) {
  if (!event) {
    return false;
  }

  if (event.isTrusted === true) {
    return true;
  }

  return event.pageX !== 0 || event.pageY !== 0;
}</code></code></pre><h3>Consumer-Driven Contracts</h3><p>Consumer-driven contracts help ensure that the interactions between different components of a software system are correct and consistent. This is particularly important in the context of microservices, where a single application may be composed of many different services that communicate with each other through APIs.</p><p>In a consumer-driven contract, the consumer of an API defines the contract that specifies the expectations for the provider of the API. This contract typically includes things like the input and output parameters of the API, as well as any constraints or requirements on the behavior of the provider. The provider then implements the API in such a way that it meets the contract defined by the consumer.</p><p>This approach has several benefits. First, it allows for more flexible and scalable testing, as the consumer can easily switch between different providers without having to rewrite their tests. This is because the consumer's tests are based on the contract, rather than the specific implementation of the provider. Second, it allows for more collaboration between the consumer and the provider, as they can work together to define the contract and ensure that it accurately reflects the needs of the consumer.</p><p>Overall, consumer-driven contracts help to ensure that the interactions between different software components are correct and consistent, which is essential for the development of robust and scalable microservice-based systems.</p><p>Read more:</p><ul><li><p><a href="https://martinfowler.com/articles/consumerDrivenContracts.html">Consumer-Driven Contracts: A Service Evolution Pattern</a></p></li></ul><h3>Community Share: Technical Debt by <a href="https://medium.com/@ahmedhassanein87">Ahmed Hassanein</a> </h3><p>In his awesome blog post, Ahmed shares how we can approach solving technical debt as it should be taken seriously and dealt with in a timely manner to avoid rooting the codebase and it is important to recognize when it is ok to leave some technical debt and when it is necessary to take the time to address it. </p><p>A few tips are:</p><ul><li><p>Include the product owner early in the process and rally your team for support</p></li><li><p>Have a meeting to discuss the pain points caused by technical debts and what are the logical approaches to solve them.</p></li><li><p>Create sub-tasks to detail the technical debt so we have a tracked ticket to solve them. Don&#8217;t solve them on-spot to avoid consuming time.</p></li><li><p>When the time for work planning arrives, vote to tackle them and hopefully you already have your team&#8217;s support</p></li><li><p>Repeat the cycle as technical debt is a long-term commitment and won&#8217;t be solved in one day</p></li></ul><p>Read the full article:</p><ul><li><p><a href="https://medium.com/front-end-weekly/technical-debt-how-to-kill-the-weeds-in-your-codebase-garden-9238a47f750e">Technical debt: How to kill the weeds in your codebase garden!</a></p></li></ul><div class="pullquote"><p>Do you write tech articles? If you're interested in having your content shared with a wider audience, please send me your links and I'll attach a summary for it here. </p><p>Let's spread knowledge &#10084;&#65039;</p></div><p></p><h3>Use <code>import</code> natively</h3><p>Browsers nowadays have native support for the <code>import</code> statement, which allows you to use JavaScript modules in your code without the need for a build tool or transpiler. This means that you can directly use the <code>import</code> statement in your JavaScript code and the browser will handle the loading and execution of the modules.</p><p>For example, In <code>button.js</code></p><pre><code><code>export function sayHello(){
  console.log("Hello World")
}
</code></code></pre><p>We can import button directly to <code>index.js</code> without bundling at all</p><pre><code><code>import { sayHello } from './src/components/button.js';

sayHello(); //"Hello World"
</code></code></pre><p>And we can include the above <code>index.js</code> in the <code>index.html</code></p><pre><code><code>&lt;!DOCTYPE html&gt;
&lt;html&gt;
  &lt;head&gt;
    &lt;title&gt;My Project&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;script type="module" src="./index.js"&gt;&lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;
</code></code></pre><p>Note that we need to define the <code>type</code> of script tag as <code>module</code> to make sure the browser understands that we can use <code>import</code> statements</p><p>This allows you to organize your code into reusable modules, making it easier to manage and maintain. It is important to note that not all browsers support this feature, and you should check for browser compatibility before using it in production.</p><p>Read more:</p><ul><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">import statement by mdn</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Issue #7: requestAnimationFrame, Web Streams and CEO-less Companies]]></title><description><![CDATA[Hey Friends,]]></description><link>https://newsletter.justenough.dev/p/issue7-requestanimationframe-web</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue7-requestanimationframe-web</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Mon, 26 Dec 2022 09:01:04 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/0ae60ae6-4a0e-4402-a1bd-a8efb274f548_960x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey Friends,</p><p>The past two weeks were relaxing so far, most of my work colleagues took long vacations like most Germans. So, it&#8217;s going to be less stressful and it&#8217;s time to reflect on this year and plan for my goals for 2023 &#128640;</p><p>I have big plans for my career like getting into Machine Learning, Data Science, and Cyber Security, and my content creation to make more videos consistently on my YouTube channel.</p><p>Wish you all a good time and prepare your amazing 2023 goals &#127919;</p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>requestAnimationFrame</h3><p>It's part of the Web APIs and it runs a function depending on the refresh rate of the screen (60 Hz, 120 Hz or 144 Hz). For example for a screen with refresh rate of 120 Hz, it will run the method for 120 time in a second.</p><p>The question that comes in mind is what is the difference between it and setInterval. and is that setInterval runs a a function based on how many times you would like to run and it's inacurate. and if we have multiple setIntervals to do two animations, they will be out of sync and consume too much GPU power</p><p>But&nbsp;requestAnimationFrame will batch those requests and do them all at once depending&nbsp;on the frequency.</p><p>Another important related method is&nbsp;cancelAnimationFrame which is like removeEventListner and it's used to cancel an animation request when we want to stop animating when the DOM element is removed for example.</p><p>requestAnimationFrame callback will get the the current timestamp and a group of batched callbacks will get the same timesatamp. If you also subtract the previous timestamp and current you will get the time period which is the inverse of the screen frequency. This is important to make sure that your animation don't run faster than needed.</p><p>requestAnimationFrame() calls are paused in most browsers when running in background tabs or hidden &lt;iframe&gt;s in order to improve performance and battery life.</p><p>More reads:</p><ul><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame">Window.requestAnimationFrame()</a></p></li><li><p><a href="https://stackoverflow.com/questions/38709923/why-is-requestanimationframe-better-than-setinterval-or-settimeout">Why is requestAnimationFrame better than setInterval or setTimeout</a></p></li><li><p><a href="https://www.youtube.com/watch?v=zBRqnSiq_VM">The Hidden World of requestAnimationFrame</a></p></li></ul><h3>Web Streams</h3><p>Web streams are APIs that allow for the delivery of multiple values or parts of a larger value gradually over time. They can be used to improve the speed of content delivery by handling and processing data bit by bit, allowing for the rendering of some content before all of the data has been received. Streams offer benefits such as the ability to handle errors and support cancellation, as well as flow control, which allows the stream to react to the speed of the reader. The fetch API now includes support for streams, allowing developers to access the underlying stream of a response object and read it in a variety of formats.</p><p>Combining Streams API + Service Workers can yield almost same or even better performance than SSR as we can cache the App and then use Service workers to stream the content from the server and show it to the user.</p><p>Read more:</p><ul><li><p><a href="https://jakearchibald.com/2016/streams-ftw/#streaming-results">2016 - the year of web streams by Jake Archibald</a></p></li></ul><h3>CEO-less Companies</h3><p>Co-op companies, also known as cooperatives, are businesses that are owned and operated by a group of people who come together to meet a common need or goal. These types of companies are typically formed to provide goods or services to their members, who are also the owners of the business. Co-op companies are based on the principles of democracy, equality, and solidarity, and profits are typically distributed among the members rather than going to external shareholders.</p><p>Do you think the current dominant company model we have where a CEO holds most of the power is more like a dictatorship?</p><div id="youtube2-4M6lrhuiPv0" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;4M6lrhuiPv0&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/4M6lrhuiPv0?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><h4>Interesting Links</h4><ul><li><p><a href="https://www.willett.io/posts/precepts/">How to Build Software like an SRE</a></p></li><li><p><a href="https://you-dont-need.github.io/You-Dont-Need-Lodash-Underscore/#/">You don't (may not) need Lodash/Underscore</a></p></li><li><p><a href="https://www.codecademy.com/article/what-is-net">What is .NET?</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Issue #6: ASCII Art, Kubernetes, ChatGPT]]></title><description><![CDATA[Hey Friends, The past two weeks were like two months of a lifetime :D I did a lot of traveling, gave a talk on Developer Productivity at work, almost got fined 60 euros for an incorrect ticket on the DB train, and spent too much time discovering ChatGPT which is part of this issue&#8217;s summary.]]></description><link>https://newsletter.justenough.dev/p/issue6-ascii-art-kubernetes-chatgpt</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue6-ascii-art-kubernetes-chatgpt</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Mon, 12 Dec 2022 09:01:04 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/da3bbc5e-f99e-4e38-a99c-908a645f0a5a_960x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey Friends,</p><p>The past two weeks were like two months of a lifetime :D</p><p>I did a lot of traveling, gave a talk on Developer Productivity at work, almost got fined 60 euros for an incorrect ticket on the DB train, and spent too much time discovering ChatGPT which is part of this issue&#8217;s summary.</p><p>Upcoming weeks will be relaxed playing some Watch Dogs Legion on my PS4 and enjoying the holidays and Christmas &#127876;</p><p>Wish you all also Happy Holidays and Merry Christmas &#127873;</p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>ASCII Art</h3><p>Past weeks, we worked on a task to show the company&#8217;s logo in the Console and my colleague, <a href="https://www.linkedin.com/in/lisa-salvesen/">Lisa</a>, told me about ASCII art which is a technique that uses the characters of the ASCII character set to create images. </p><p>To create ASCII art, we typically use the characters in the ASCII character set to represent different shades of gray or colors. For example, the character "." might be used to represent the lightest shade of gray, while the character "8" could be used to represent a darker shade. We can then combine these characters to create a picture or image.</p><p>ASCII art is often used in computer programs and online forums as a form of artistic expression. It is a popular way to create and share art online, and many websites and forums have dedicated sections for ASCII art. Some people even use ASCII art as a form of digital graffiti, posting it on websites and forums without the permission of the site's owner. Despite its limitations, ASCII art continues to be a popular and creative way for people to express themselves online.</p><p>Find more:</p><ul><li><p><a href="https://www.youtube.com/watch?v=55iwMYv8tGI">Coding Challenge 166: ASCII Text Images</a></p></li></ul><h3>Kubernetes</h3><p>Kubernetes is an open-source platform for automating the deployment, scaling, and management of containerized applications. It consists of several components that work together to provide a complete solution for managing and deploying applications. Some of the key components of Kubernetes include:</p><ul><li><p>The Kubernetes master: This is the main control plane for the Kubernetes cluster. It consists of several components, such as the API server, which is the main entry point for interacting with the cluster, and the etcd distributed key-value store, which stores the cluster's configuration data.</p></li><li><p>The Kubernetes nodes: These are the worker machines that run the containerized applications. Each node runs a kubelet, which is the agent that communicates with the Kubernetes master and manages the containers on the node.</p></li><li><p>The Kubernetes pod: This is the basic unit of deployment in Kubernetes. A pod is a logical host for one or more containers, which share the same network namespace and can communicate with each other easily.</p></li><li><p>The Kubernetes deployment: This is a higher-level object that manages the deployment and scaling of one or more replicas of a pod. The deployment manages the rolling update process, which allows you to update the containers in a pod without downtime.</p></li><li><p>The Kubernetes service: This is an abstract way to expose the pods to the outside world. A service defines a logical set of pods and a policy for accessing them, and it provides a stable IP address and DNS name for the pods.</p></li></ul><p>Read more:</p><ul><li><p>This is <a href="https://github.com/abduvik/just-enough-series/tree/kubernetes-v1/courses/kubernetes">an upcoming full summary on Kubernetes</a> that I am preparing and will make a video for it.</p></li></ul><h3>ChatGPT</h3><p>I think this has been the hype for the past few weeks and probably you have used it or knew someone used it. If not, it&#8217;s basically a general-purpose chat AI developed by OpenAI. It can answer any question you ask it and it will reply with a good answer.</p><p>I asked it to write a poem on Kubernetes, solve global warming, some political questions, translate text into German with a Bavarian dialect, and even asked it questions in Arabic with an Egyptian Dialect.</p><p>Of course, I am aware it doesn&#8217;t understand what I mean and it lacks creativity as it&#8217;s eventually a model trained on a massive amount of data. It&#8217;s similar to AI models used to predict the stock market, they are good for past predictions but not for the unknown future which still requires the creativity of the human element.</p><p>It&#8217;s a great tool to try and learn as it can be integrated into your workflow and multiply your productivity similar to what Github Co-pilot is doing now.</p><p>Read more:</p><ul><li><p><a href="https://openai.com/blog/chatgpt/">ChatGPT by OpenAI</a></p></li></ul><div><hr></div><h4>Non-tech Interesting Video</h4><h3><strong>What&#8217;s Really Happening in the Bermuda Triangle</strong></h3><div id="youtube2-112H-vY4Wdo" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;112H-vY4Wdo&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/112H-vY4Wdo?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div>]]></content:encoded></item><item><title><![CDATA[Issue #5: Fluent Interface, getComputedStyle, NPM Dependency configs]]></title><description><![CDATA[Fluent Interface, getComputedStyle, NPM Dependency configs]]></description><link>https://newsletter.justenough.dev/p/issue5</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue5</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Mon, 28 Nov 2022 09:01:02 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/5a7ae662-aa59-4a5b-836a-539823a50ac2_960x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey Friends,</p><p>It has been a while since I was able to send newsletters but I managed to adjust my schedule now and it hopefully would work this time.</p><p>This week I am going to do a lot of traveling. To Passau, Munich, and Dresden and get my React free course ready, and publish it on my channel. It will include a bonus section about SSR in a new unique way not found on other tutorials and courses.</p><p>A long week is coming up but hopefully will be productive and I wish you as well a productive nice start to the week :)</p><div><hr></div><h4>This week&#8217;s Summaries</h4><h3>Fluent Interface</h3><p>It&#8217;s the concept of creating a more &#8220;Fluent&#8221; code that is easier to read by chaining methods. Here, methods on their own don&#8217;t show their intent but chaining them shows a more declarative meaning.</p><p>The best examples are: LINQ queries in C#, Jest &amp; jQuery in Javascript, and jMock in Java.</p><pre><code><code>IEnumerable&lt;string&gt; query = translations
&#9;.Where(t =&gt; t.Key.Contains("a"))
&#9;.OrderBy(t =&gt; t.Value.Length)
&#9;.Select(t =&gt; t.Value.ToUpper());</code></code></pre><p>Read More:</p><ul><li><p><a href="https://martinfowler.com/bliki/FluentInterface.html">Fluent Interface by Martin Fowler</a></p></li><li><p><a href="https://en.wikipedia.org/wiki/Fluent_interface">Fluent Interface on Wikipedia</a></p></li></ul><h3>getComputedStyle</h3><p>One task I needed to deal with the past week is to find a way to set a child&#8217;s <code>height</code> based on the parent&#8217;s CSS <code>min-height</code>.</p><p>Problem is that there is no DOM property to get this <code>minHeight</code>.</p><p>A quick search and I came across a DOM API called <code>getComputedStyle</code> and it returns the computed style of the component based on the different classes and styles and CSS properties including the <code>minHeight</code> that I needed.</p><pre><code><code>getComputedStyle(element)
getComputedStyle(element, pseudoElt)</code></code></pre><p>Read more:</p><ul><li><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/Window/getComputedStyle">MDN docs on getComputedStyle</a></p></li></ul><h3>dependency vs devDependencies vs peerDependencies</h3><p>They are how we define dependencies in Javascript-based projects</p><ul><li><p><code>"dependencies"</code>: Packages required by your application in production.</p></li><li><p><code>"devDependencies"</code>: Packages that are only needed for local development and testing. NPM won&#8217;t install them when someone installs our dependency.</p></li><li><p><code>"peerDependencies": </code>When someone installs our package, our package expects theirs to have these dependencies. If they don&#8217;t have it, NPM will still install them</p></li></ul><p>Read more:</p><ul><li><p><a href="https://www.youtube.com/watch?v=PxJ5wzFPTFU">dependencies vs devDependencies vs peerDependencies in package.json</a></p></li></ul><div><hr></div><h4>Interesting Video</h4><p><a href="https://www.youtube.com/watch?v=STKCRSUsyP0">The Many Meanings of Event-Driven Architecture by Martin Fowler @ GOTO 2017</a></p><div id="youtube2-STKCRSUsyP0" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;STKCRSUsyP0&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/STKCRSUsyP0?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div>]]></content:encoded></item><item><title><![CDATA[Issue #4: HoC vs Inheritance, MutationObserver and Webpack]]></title><description><![CDATA[Hey Friends!]]></description><link>https://newsletter.justenough.dev/p/issue-4-hoc-vs-inheritance-mutationobserver</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-4-hoc-vs-inheritance-mutationobserver</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Thu, 05 May 2022 14:00:40 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/26212805-fead-4d27-b6cc-3eec73065dd9_960x600.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Hey Friends!</p><p>I hope this week has been going great for you so far and everything is going well and you getting ready for the weekend ^_^</p><p>I apologize for not posting any newsletters over the past weeks but I am back again and stronger than ever and hopefully we share our knowledge together!</p><p>Hope you will like this Newsletter Issue, Enjoy!</p><div><hr></div><h2>HoC vs Inheritance</h2><p>Higher-Order Component or HoC is a way to add extra stuff over a function or an object. We basically &#8220;curry&#8221; it by wrapping the original function with extra logic.</p><pre><code>withLogging(component){
   console.log('I am an HoC');
   return function(){
       return component;
   }
}

const button = () =&gt; document.createElement('button')

const buttonWithLogging = withLogging(button());
</code></pre><p>But you might ask what is the difference between it and inheritance then.</p><p>And it&#8217;s the idea of reusing the logic again with other components to create new components with the same logic.</p><p>Another thing I have noticed while playing with VueJs is that VueJs has mixins that do a very similar job to HoC</p><p>Except that mixins will overwrite the existing options aka. inheritance while HoC will isolate the original component and wrap it with a new extra logic</p><p>It basically a form of the Adapter or Proxy design pattern.</p><h2>MutationObserver</h2><p>It&#8217;s a native JavaScript interface that provides the ability to watch changes that happens to the DOM. It&#8217;s like the reverse of what UI libraries do. So instead of React or Vue for example changing the DOM, you can create a listener on the DOM to listen to these manipulations and apply a certain method or effect when this happens.</p><p>I encountered it while I was trying to search for a way to listen to CSS changes and this was a supported method to apply it</p><p><a href="https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver">You can read more about it in the official documentation</a></p><p>Example code from the documentation</p><pre><code>// Select the node that will be observed for mutations
const targetNode = document.getElementById('some-id');

// Options for the observer (which mutations to observe)
const config = { attributes: true, childList: true, subtree: true };

// Callback function to execute when mutations are observed
const callback = function(mutationsList, observer) {

    // Use traditional 'for loops' for IE 11
    for(const mutation of mutationsList) {
        if (mutation.type === 'childList') {
            console.log('A child node has been added or removed.');
        } else if (mutation.type === 'attributes') {
            console.log(
              `The ${mutation.attributeName} attribute was modified.`
            );
        }
    }
};

// Create an observer instance linked to the callback function
const observer = new MutationObserver(callback);

// Start observing the target node for configured mutations
observer.observe(targetNode, config);

// Later, you can stop observing
observer.disconnect();</code></pre><h2>Monorepo</h2><p>We spoke about Monorepos in a previous Issue and now I have created a <em>Just Enough Monorepo</em> video that should cover everything you will need to understand the concepts behind Monorepos.</p><div id="youtube2-N5pjlJnzrSw" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;N5pjlJnzrSw&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/N5pjlJnzrSw?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>Monorepo is a repository set up to have different parts of your application microservices under a single repository to improve productivity.</p><p>If you have multiple packages or components that depend on each other, they usually have similar scripts, commands, and dependencies, then having a single repository with everything will reduce the number of duplications, and make it easy to access and update different modules and publish different versions at once. It will dramatically increase your team's productivity.</p><div><hr></div><h2>Something Made Me Laugh :D</h2><div id="youtube2-Uo3cL4nrGOk" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;Uo3cL4nrGOk&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/Uo3cL4nrGOk?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><h2>Interesting Links</h2><ul><li><p><a href="https://sre.google/resources/">Google&#8217;s Site Reliability Engineering</a></p></li><li><p><a href="https://chrome.google.com/webstore/detail/the-marvellous-suspender/noogafoofpebimajpfpamcfhoaifemoa?hl=en">The Marvellous Suspender&#9;Link</a></p></li><li><p><a href="https://patterns.dev/">Patterns.dev by Lydia Hallie and Addy Osmani</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Issue #3: JS Imports, TabIndex and NFTs]]></title><description><![CDATA[...and how to maintain focus during a work day]]></description><link>https://newsletter.justenough.dev/p/issue3-js-imports-tabindex-and-nfts</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue3-js-imports-tabindex-and-nfts</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Thu, 06 Jan 2022 08:02:39 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/8fd38d3e-0e6a-4d7c-8688-18bab759d9c4_1280x800.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SVzk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4630812a-8b56-4547-9270-adbd9bd23a4e_1075x519.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SVzk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4630812a-8b56-4547-9270-adbd9bd23a4e_1075x519.jpeg 424w, https://substackcdn.com/image/fetch/$s_!SVzk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4630812a-8b56-4547-9270-adbd9bd23a4e_1075x519.jpeg 848w, https://substackcdn.com/image/fetch/$s_!SVzk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4630812a-8b56-4547-9270-adbd9bd23a4e_1075x519.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!SVzk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4630812a-8b56-4547-9270-adbd9bd23a4e_1075x519.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SVzk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4630812a-8b56-4547-9270-adbd9bd23a4e_1075x519.jpeg" width="1075" height="519" data-attrs="{&quot;src&quot;:&quot;https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/4630812a-8b56-4547-9270-adbd9bd23a4e_1075x519.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:519,&quot;width&quot;:1075,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:48846,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!SVzk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4630812a-8b56-4547-9270-adbd9bd23a4e_1075x519.jpeg 424w, https://substackcdn.com/image/fetch/$s_!SVzk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4630812a-8b56-4547-9270-adbd9bd23a4e_1075x519.jpeg 848w, https://substackcdn.com/image/fetch/$s_!SVzk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4630812a-8b56-4547-9270-adbd9bd23a4e_1075x519.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!SVzk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fbucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com%2Fpublic%2Fimages%2F4630812a-8b56-4547-9270-adbd9bd23a4e_1075x519.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h1>Technical Summaries</h1><h3>Default Import vs Alias Import</h3><p>For example, it&#8217;s the difference between </p><pre><code>import react from 'React'

// vs 

import * as react from 'React'</code></pre><p>The first one will only import the default exports but the second one will import all exports.</p><p>The correct one to use is the latter one per what Dan said and is also mentioned <a href="https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html#removing-unused-react-imports">in the React Docs</a></p><div class="twitter-embed" data-attrs="{&quot;url&quot;:&quot;https://twitter.com/dan_abramov/status/1308739731551858689?lang=en&quot;,&quot;full_text&quot;:&quot;<span class=\&quot;tweet-fake-link\&quot;>@kentcdodds</span> <span class=\&quot;tweet-fake-link\&quot;>@jacobmparis</span> To clarify:\n\n&#9989; import { useState } from 'react'\n&#9989; import * as React from 'react'\n&#128993; import React from 'react'\n\nThe third one is called \&quot;default import\&quot; and in the long term (maybe in 19 or 20) we will stop supporting it. We provide an automated script to change it.&quot;,&quot;username&quot;:&quot;dan_abramov&quot;,&quot;name&quot;:&quot;Dan&quot;,&quot;profile_image_url&quot;:&quot;&quot;,&quot;date&quot;:&quot;Wed Sep 23 12:07:21 +0000 2020&quot;,&quot;photos&quot;:[],&quot;quoted_tweet&quot;:{},&quot;reply_count&quot;:0,&quot;retweet_count&quot;:80,&quot;like_count&quot;:264,&quot;impression_count&quot;:0,&quot;expanded_url&quot;:{},&quot;video_url&quot;:null,&quot;belowTheFold&quot;:false}" data-component-name="Twitter2ToDOM"></div><h3>Tabindex=-1</h3><p>A&nbsp;negative value&nbsp;(usually&nbsp;<code>tabindex="-1"</code>) means that the element is not reachable via sequential keyboard navigation, but could be focused with JavaScript or visually by clicking with the mouse. It's mostly useful to create accessible widgets with JavaScript.</p><p>It helped me when a modal opened and I wanted to close it when keydown Esc but at the same time I didn't want to attach the event to the body as it's not its concern and divs can&#8217;t listen on keydown events. So if you add the negative tabindex, it can now listen and you can focus it without affecting the normal tab sequence follow in the browser.</p><h3>What are NFTs?</h3><p>I am sure you have heard this word like a thousand times and still wonder what it is. In the very short term, you basically own a hash that represents a certain art like images for example and everyone agrees that you own that hash code. But the art itself is something that can be copied or used by anyone.</p><p>But then why it&#8217;s being sold very expensive you may ask? Imagine if I told you I will sell you some sand, you will say no thank you but if I told you this sand was in the hands of let&#8217;s say Queen Elizabeth or Elon Musk, probably you would assign some value to it, let&#8217;s say $10 and then you go to sell it to someone else to make a difference and so on.</p><p>That&#8217;s why it&#8217;s just another type of speculative asset. The bread you bake is worth to you a hundred times over the one you buy from the bakery because it has a story to you.</p><p>You can watch this video to get more details if you are interested</p><div id="youtube2-Oz9zw7-_vhM" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;Oz9zw7-_vhM&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/Oz9zw7-_vhM?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><div><hr></div><h3>How to Maintain Focus at Work for Software Developers</h3><p>Instant notifications, ad-hoc calls, slack messages, emails... an overwhelming load on our human brain to stay focused during a typical workday as software developers.<br><br>With all of these distractions, we will try to abstract some processes to lower their effects and how to live with them as they won't disappear any time soon.<br><br>Check out the new video from "Skilled Engineer" series</p><div id="youtube2-j6uNhhoyTLY" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;j6uNhhoyTLY&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/j6uNhhoyTLY?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>or <a href="https://abduvik.medium.com/how-to-maintain-focus-at-work-for-software-developers-1248a084ea64">read the full article</a>.</p><h4>Summary:</h4><ul><li><p>Balanced-life in Sport, Nutrition, and Sleep</p></li><li><p>Have 2 golden hours</p></li><li><p>Snooze with Pomodoro</p></li><li><p>Work with intention</p></li><li><p>Have discipline by tracking progress</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Issue #2: Git Rebase vs Merge, Software Release Cycle and Keycloak ]]></title><description><![CDATA[Quick Update: I am going to reduce the frequency of the newsletter to be bi-weekly every Thursday so you could receive it consistently and I would be able to commit to it. Technical Summaries Git Rebase vs Git merge They are very similar when comes to adding commits from a branch into the current branch. But the difference is that when you merge, you add the source branch to the top of the current branch, but with rebase, you will add the current branch&#8217;s base on top of the source branch.]]></description><link>https://newsletter.justenough.dev/p/issue-2-git-rebase-vs-merge-software</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-2-git-rebase-vs-merge-software</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Thu, 23 Dec 2021 08:00:35 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/dad915a5-7fdb-4886-ad09-8f55c35fca42_1280x800.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em><strong>Quick Update:<br>I am going to reduce the frequency of the newsletter to be bi-weekly every Thursday so you could receive it consistently and I would be able to commit to it.</strong></em></p><div><hr></div><h1>Technical Summaries</h1><h2>Git Rebase vs Git merge</h2><p>They are very similar when comes to adding commits from a branch into the current branch. But the difference is that when you merge, you add the source branch to the top of the current branch, but with rebase, you will add the current branch&#8217;s base on top of the source branch.</p><p>Merge will keep the history, but rebase will change it.</p><p>Merge will be good when collaborating with other developers so as not to break their local git histories but rebase is good to keep the git history clean.</p><p>But in my opinion, realistically rebase will always become annoying if you work in a multi-developer branch which is the most common case. And rebase&#8217;s value is not comparable to having a good developer experience.</p><p>If you are the sole developer for a branch or you still haven&#8217;t pushed your commits then it&#8217;s okay, otherwise, always use merge.</p><p><em><strong>More Reading:</strong> <a href="https://stackoverflow.com/questions/804115/when-do-you-use-git-rebase-instead-of-git-merge">When do you use git rebase instead of git merge</a></em></p><h2><strong>Software Release Life Cycle</strong></h2><p>By no means this is something official and should be taken with a grain of salt and every company have its own adapted process and some do all of these steps in a matter of days or even hours especially for web applications</p><ul><li><p><strong>Alpha:</strong> Planning, analysis, development, unit testing, quality testing, and value assurance. Still might be unstable and have serious bugs. Software is still inside the organization and it may not contain all features planned for the final release. The phase ends with a feature freeze when all is done and ready for thorough beta testing.</p></li><li><p><strong>Beta:</strong> Can be available publically. Usability testing is done at this stage and more bugs are closed. Closing major bugs or blockers.</p></li><li><p><strong>Release Candidate:</strong> All features are completed and no more features need to be added for the stable release. Documentation is done.</p></li><li><p><strong>Stable Release:</strong> Production release and marks the latest release candidate as done.</p></li><li><p><strong>Support:</strong> Includes patches and service packs for version maintenance, enhancements, and fixes</p></li><li><p><strong>End-of-life:</strong> When it&#8217;s deprecated and no longer supported but might still be used by customers</p></li></ul><p><em><strong>More Reading:</strong> <a href="https://en.wikipedia.org/wiki/Software_release_life_cycle">Software Release Life Cycle</a></em></p><h2><strong>Keycloak</strong></h2><p>A complete solution to manage user authentication and authorization and it&#8217;s very easy to customize. This is really good for apps that need quick prototyping and don&#8217;t have time to create such solutions and at the same time, they need their data to be away from using cloud authentication services on AWS or GCP.</p><p>The only reason you might not use it is if you want to stay away from Java or you don&#8217;t have Java experience. Otherwise, go for it!</p><div id="youtube2-duawSV69LDI" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;duawSV69LDI&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/duawSV69LDI?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p><strong>More Reading:</strong> <a href="https://www.keycloak.org/">Keycloak Main Website</a></p><div><hr></div><h1>Weekly YouTube Video</h1><p>Starting a new job, whether it&#8217;s the first one or switching companies, it&#8217;s always exciting at first but without preparation and having a target with a defined plan, you might find yourself searching for a new one sooner and trying to escape it. </p><p>We will discuss in this episode from <strong>"Skilled Engineer"</strong> a structured way to control and conquer your new job with less anxiety and they have helped me with my new position and it will surely help you too.</p><div id="youtube2-s7RKvGT6ZJo" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;s7RKvGT6ZJo&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/s7RKvGT6ZJo?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div>]]></content:encoded></item><item><title><![CDATA[Issue #1: Monorepos, Test-Doubles, Jest Mocks]]></title><description><![CDATA[Technical Summaries, Useful Links, Personal News, Weekly Video]]></description><link>https://newsletter.justenough.dev/p/issue-1-monorepos-test-doubles-jest</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/issue-1-monorepos-test-doubles-jest</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Thu, 16 Dec 2021 16:17:04 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/930581dd-a070-4c00-9b29-37020d96815f_1280x800.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>Thanks for subscribing to my newsletter </em>&#10084;<em><br>Although I have promised to start it a while ago, <br>I now have more time to return back creating and posting content starting from today!<br>Every Thursday, there will be a new newsletter sent, so keep tuned and tell your friends </em>&#128522;</p><div><hr></div><h1>Technical Summaries</h1><h3>Monorepos</h3><p>Monorepo is a repository configuration to avoid having multiple repositories for your project. If you have multiple packages or components that depend on each other, they usually have similar scripts, commands, and dependencies, then having a single repository  with everything will reduce the number of duplications, and make it easy to access and update different modules and publish different versions at once. It will dramatically increase your team's productivity.</p><p>Here is a quick summary of what needs to be done to allow Monorepos for a Javascript/Typescript project and can work with Nodejs too:</p><ul><li><p><strong>Package Management:</strong> Enable <em><a href="https://docs.npmjs.com/cli/v7/using-npm/workspaces">npm workspaces mode</a></em> by setting the main package.json file `<code>private: true</code>` and adding the `<code>workspaces</code>` to an array of available packages. You can use a wildcard `<code>packages/*</code>` to apply for all.</p></li><li><p><strong>Typescript:</strong> We need to create three tsconfig files; one which will be the main tsconfig file with all needed configs, the second one to import these configs inside each project and a third one is used to reference and build all projects with a single `<code>tsc --build</code>`. First, create the tsconfig at the top level, and then inside each project use the property `<code>extends</code>` and then pass a reference to the main JSON file with the full typescript configs needed. The build tsconfig file would be a separate file that has two properties; the property `<a href="https://www.typescriptlang.org/docs/handbook/project-references.html"><code>references</code></a>` set to point to every project and `<a href="https://www.typescriptlang.org/tsconfig#files"><code>files: []</code></a>` which is an empty array to avoid building the project twice.</p></li><li><p><strong>Babel:</strong> You can create a main <code>.babelrc</code> file and then reference it inside each projects&#8217; <code>.babelrc</code> with the property `<code>extends: &lt;path&gt;</code>`</p></li><li><p><strong>ESLint:</strong> Same like Babel we create `<code>.eslintrc</code>` file but on the root directory as IDEs tend to prefer them on the root to enforce the rules and then for each project you can create an internal config `<code>.eslintrc</code>` file and use the `<code>extend</code>` property.</p></li><li><p><strong>Lerna:</strong> It provides good tooling for Monorepos like running a certain command across all repositories, and linking between packages</p></li><li><p><strong>Scripty:</strong> Tool to manage scripts inside package.json and unify all of them in shell file instead of having a long command in package.json file.</p></li><li><p><strong>commitlint:</strong> In a Monorepo where many teams work together, it&#8217;s a great idea to unify how commits are made and their format and also supports automatic changelog. Using Lerna with commitlint and husky will do the required things and setup is very easy. <a href="https://github.com/conventional-changelog/commitlint">Follow this link</a>.</p></li></ul><h3>Test Doubles</h3><div id="youtube2-BNXPRIscfQ8" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;BNXPRIscfQ8&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/BNXPRIscfQ8?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div><p>We know tests contain E2E, Integration, and Unit tests. We use test doubles when we have indirect inputs (like queries), indirect outputs (like sending events to events stream or when you call API),  or slow tests (when you call the server or the database or over the network). These mocks can have different types:</p><ul><li><p>Mocks: This is an object that you record what you do to it and record data and you can verify what has been done to the mock object. It&#8217;s more for testing behaviors.</p></li><li><p>Stubs: Are simple and they provide indirect inputs for the system. It&#8217;s more for testing the state. Stubs never fail a test but mocks can (like out of order process). You assert against mocks but not against Stubs.</p></li><li><p>Spies: They have a Call log, a Response list, and State Access. They are stubs but with a call log and they intercept real pieces of code.</p></li><li><p>Dummies: Just values holder</p></li><li><p>Fakes: replace real implementation with a fake implementation to simulate situations or for making tests faster. They </p></li></ul><p><em>Note: across the community, the naming might be different and not unified. It&#8217;s enough to get the idea about them and use the proper construct</em></p><h3>Jest mocks</h3><p>For unit tests instead of including a module that has long nested children that we don&#8217;t care about, you can use the `<code>mock</code>` function to mock these internal libraries</p><pre><code>jest.mock('../UserListContainer', () =&gt; () =&gt; 'UserListContainer');</code></pre><p>Just make sure that the path is relative to the testing file and not the component</p><h1>Useful Links</h1><ul><li><p><a href="https://frontendmasters.com/courses/monorepos/">Javascript and Typescript Monorepos</a></p></li><li><p><a href="https://www.btw.so/open-source-alternatives/">Open Source Alternatives</a></p></li><li><p><a href="https://stackoverflow.com/questions/3459287/whats-the-difference-between-a-mock-stub">What's the difference between a mock &amp; stub?</a></p></li><li><p><a href="http://xunitpatterns.com/Test%20Double.html">Test Double</a></p></li><li><p><a href="https://jestjs.io/docs/jest-object#mock-modules">Jest Mock Modules</a></p></li></ul><h1>Personal News</h1><p><em>&#8212;I will leave this as a blank for now and you can reply to this email with what you like to know and hear about</em> &#128522;&#8212;</p><h1>Weekly YouTube Video</h1><div id="youtube2-clW97khzwEo" class="youtube-wrap" data-attrs="{&quot;videoId&quot;:&quot;clW97khzwEo&quot;,&quot;startTime&quot;:null,&quot;endTime&quot;:null}" data-component-name="Youtube2ToDOM"><div class="youtube-inner"><iframe src="https://www.youtube-nocookie.com/embed/clW97khzwEo?rel=0&amp;autoplay=0&amp;showinfo=0&amp;enablejsapi=0" frameborder="0" loading="lazy" gesture="media" allow="autoplay; fullscreen" allowautoplay="true" allowfullscreen="true" width="728" height="409"></iframe></div></div>]]></content:encoded></item><item><title><![CDATA[Software Summaries]]></title><description><![CDATA[Weekly Newsletter Summary Of Abdu's Personal Online Learning]]></description><link>https://newsletter.justenough.dev/p/newsletter</link><guid isPermaLink="false">https://newsletter.justenough.dev/p/newsletter</guid><dc:creator><![CDATA[Abdu Taviq]]></dc:creator><pubDate>Thu, 21 Jan 2021 17:17:19 GMT</pubDate><enclosure url="https://bucketeer-e05bbc84-baa3-437e-9518-adb32be77984.s3.amazonaws.com/public/images/2e1bf7b0-3cea-4415-afc0-c083402c0c55_1280x1280.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Welcome to my weekly newsletter where I will be sharing software knowledge I have learned during the week. I spend on average 14-17 hours per week studying and learning about how to build better software. </p><p>You will get this knowledge condensed in a weekly newsletter with links to resources to expand your software skills.</p><p>For the first 2000 active subscribers, it will be free forever!</p><p>Sign up now so you don&#8217;t miss the first issue.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://newsletter.justenough.dev/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://newsletter.justenough.dev/subscribe?"><span>Subscribe now</span></a></p><p>In the meantime, <a href="https://newsletter.justenough.dev/p/newsletter?utm_source=substack&utm_medium=email&utm_content=share&action=share">tell your friends</a>!</p><div><hr></div><p><em>Social media:&nbsp;<a href="https://twitter.com/abduvik">Twitter</a>,&nbsp;<a href="https://www.youtube.com/channel/UChwFTWeegBqO6pRPAQkthIw">YouTube</a>,&nbsp;<a href="https://www.linkedin.com/in/abduvik/">LinkedIn</a>,&nbsp;<a href="https://www.instagram.com/abduvik/">Instagram</a>, and&nbsp;<a href="https://github.com/abduvik">GitHub</a></em></p>]]></content:encoded></item></channel></rss>