<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Alvin Bryan</title>
    <description>The latest articles on Forem by Alvin Bryan (@alvinb).</description>
    <link>https://forem.com/alvinb</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F484501%2Faa0aac70-5c0e-49f1-8fb2-e346f218ec15.jpeg</url>
      <title>Forem: Alvin Bryan</title>
      <link>https://forem.com/alvinb</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/alvinb"/>
    <language>en</language>
    <item>
      <title>Tips to remember latitude and longitude</title>
      <dc:creator>Alvin Bryan</dc:creator>
      <pubDate>Fri, 28 Oct 2022 11:03:05 +0000</pubDate>
      <link>https://forem.com/alvinb/tips-to-remember-latitude-and-longitude-2aom</link>
      <guid>https://forem.com/alvinb/tips-to-remember-latitude-and-longitude-2aom</guid>
      <description>&lt;p&gt;I like coding maps, but I would always forget how to remember latitude and longitude. I would always mix them up. I tried some mnemonic techniques (like, latitudes = ladder) but none of them ever worked.&lt;/p&gt;

&lt;p&gt;Here are a couple of tips to remember latitude and longitude.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. X/Y coordinates
&lt;/h2&gt;

&lt;p&gt;Tip #1: The simplest, but not the easiest, is to memorise this:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Latitude is y and longitude is x.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BQrFi5lr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ib4e9uno53xdfaihwwox.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BQrFi5lr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ib4e9uno53xdfaihwwox.png" alt="Image description" width="562" height="376"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it, Latitude is the y axis and longitude is the x axis.&lt;/p&gt;

&lt;p&gt;I tried that but would still mix them up at times. So I came up with the next tip.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. The long side of a world map
&lt;/h2&gt;

&lt;p&gt;Tip #2: If you think of a world map, usually it’s a rectangle.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The &lt;em&gt;long&lt;/em&gt; side (the largest side) is the longitude.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hRaroZ1Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sarn2zjes7pn5t64mdjg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hRaroZ1Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/sarn2zjes7pn5t64mdjg.png" alt="Image description" width="573" height="416"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Orientation
&lt;/h2&gt;

&lt;p&gt;The point at 0,0 is the intersection of the Equator and the Meridian of Greenwich. The greater the distance to them, the greater the latitude/longitude. East of the meridian gives you a positive longitude value, and west gives you a negative one. Same for north/south of the Equator.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
Prague has a larger longitude (14.43) than Paris (2.35) because it's further east. Ergo for San Francisco having a larger value (-122) than Washington DC (-77) because it's further west.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cDj_JRRX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ncdp141pbj68lb1v3u2t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cDj_JRRX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ncdp141pbj68lb1v3u2t.png" alt="Image description" width="572" height="384"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are the rounded coordinates (in the order latitude, longitude) of some popular cities to help you.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;London&lt;/strong&gt;: 51.501, -0.118. (Greenwich is in London, hence the zero longitude)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sydney&lt;/strong&gt;: -33.865, 151.210&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tokyo&lt;/strong&gt;: 35.653, 139.839&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Singapore&lt;/strong&gt;: 1.290, 103.852&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Los Angeles&lt;/strong&gt;: 34.052, -118.244&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Oslo&lt;/strong&gt;: 59.911, 10.758&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's a bonus factoid for people in the UK, Edinburgh's main train station is &lt;em&gt;further west&lt;/em&gt; (55.95, -3.18) than Liverpool's (53.40, -2.97).&lt;/p&gt;

&lt;p&gt;I hope it helps, good luck!&lt;/p&gt;

</description>
      <category>map</category>
      <category>d3</category>
      <category>beginners</category>
    </item>
    <item>
      <title>How ethical alternatives succeed: a Signal case study</title>
      <dc:creator>Alvin Bryan</dc:creator>
      <pubDate>Thu, 16 Jun 2022 09:54:58 +0000</pubDate>
      <link>https://forem.com/alvinb/how-ethical-alternative-succeed-a-signal-case-study-5a22</link>
      <guid>https://forem.com/alvinb/how-ethical-alternative-succeed-a-signal-case-study-5a22</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Here's a story about the tick that beat the giant with a trick&lt;br&gt;
— Smith and Thell, &lt;strong&gt;Goliath&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In January 2021, Signal was only known by journalists and privacy geeks. In a matter of days, it topped the charts and was on everyone's phones.&lt;/p&gt;

&lt;p&gt;How did that happen?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Signal was an overnight success that was years in the making. The app had all the components that any alternative product needs to succeed:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Zero or low switching cost, which means:

&lt;ol&gt;
&lt;li&gt;A seamless transition process&lt;/li&gt;
&lt;li&gt;Feature parity, almost&lt;/li&gt;
&lt;li&gt;Intuitive design&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;Issues with the status quo, i.e., a villain. The reason to switch has to be well-known and &lt;em&gt;relatable&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;Street credentials. If shouldn't be &lt;em&gt;just you&lt;/em&gt; recommending the alternative.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  What's the deal with WhatsApp and Signal?
&lt;/h2&gt;

&lt;p&gt;WhatsApp, owned by Facebook/Meta is one of the main secure messaging apps. Signal is a similar app run by a non-profit with a small team. Interestingly, it was the Signal team that implemented WhatsApp's encryption.&lt;/p&gt;

&lt;p&gt;These apps coeixsted for a while. WhatsApp was the mainstream app that almost everyone used, and Signal was the unknown that only journalists and privacy geeks used. Until everything changed.&lt;/p&gt;

&lt;p&gt;One day, on January 2021 WhatsApp sent a notification to its users regarding a new privacy policy. The notification said that from 8th February, WhatsApp would start sharing data with its parent company (Facebook). The Internet started writing about the changes, and people started switching to Signal. A snowball effect ensued.&lt;/p&gt;

&lt;h3&gt;
  
  
  The overnight success
&lt;/h3&gt;

&lt;p&gt;Signal became the &lt;a href="https://twitter.com/signalapp/status/1347699781326438404"&gt;most downloaded app&lt;/a&gt; in the App Store in India, Germany, France, Austria, Finland, Hong Kong, and Switzerland. The downloads went from &lt;strong&gt;246,000 the week before&lt;/strong&gt; the WhatsApp change to &lt;a href="https://www.bbc.co.uk/news/technology-55684595"&gt;&lt;strong&gt;8.8 million the week after&lt;/strong&gt;&lt;/a&gt;. Facebook even &lt;a href="https://twitter.com/signalapp/status/1348079223701794819"&gt;bought ads&lt;/a&gt; for the word "signal" to prevent people from downloading it. 3 months after the initial incident, Facebook &lt;a href="https://signal.org/blog/the-instagram-ads-you-will-never-see/"&gt;closed Signal's Instagram account&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This overnight success is attributed to Elon Musk &lt;a href="https://twitter.com/elonmusk/status/1347165127036977153"&gt;advising people to "use Signal" on Twitter&lt;/a&gt;. While it made a &lt;em&gt;gigantic&lt;/em&gt; difference, I don't think that's why it worked.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If Elon tweets "use Linux" tomorrow, no one will care. Why did "use Signal" work so well?&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  I. Zero or low switching cost
&lt;/h2&gt;

&lt;p&gt;Convenience is everything.&lt;/p&gt;

&lt;h3&gt;
  
  
  1) A seamless transition process.
&lt;/h3&gt;

&lt;p&gt;There are 4 steps to get on WhatsApp: Download the app, give it a phone number, wait for the text, and give it access to your contacts. That's it. For Signal, it's the exact same process. If Signal asked you to create an account, wait for a confirmation email, type a bio, enter a location, refer a friend, use a two-factor code, &lt;em&gt;plus the other 4 steps&lt;/em&gt;, I wouldn't be writing this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It should be as easy as possible to transition to the alternative&lt;/strong&gt;. Otherwise people won't bother.&lt;/p&gt;

&lt;h3&gt;
  
  
  2) Feature parity, almost.
&lt;/h3&gt;

&lt;p&gt;Open-source developers tend to pay too much attention to the specifics. In our case, Signal didn't have &lt;em&gt;exactly&lt;/em&gt; the same features as WhatsApp. You couldn't search Emojis by their name, it didn't support group calls with more than 5 people, and the group admin features were limited. But it had most of the features that most people wanted.&lt;/p&gt;

&lt;p&gt;It offered, all in all, a user experience that was &lt;em&gt;similar enough&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Today, not only did Signal add all these missing features, it did so without sacrificing security and privacy. Continuing on my example with group calls, Signal now support group calls with up to 40 participants. That required &lt;a href="https://signal.org/blog/how-to-build-encrypted-group-calls/"&gt;a lot of engineering&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  3) Intuitive design
&lt;/h3&gt;

&lt;p&gt;The design of the the product must be pleasant, and easy to use. &lt;strong&gt;You should never have to learn a new app&lt;/strong&gt;. Signal had a simple design without bells and whistles.&lt;/p&gt;

&lt;h2&gt;
  
  
  II. Issues with "the status quo"
&lt;/h2&gt;

&lt;p&gt;Why would you switch when the current product works?&lt;/p&gt;

&lt;p&gt;Claims like "It's Photoshop but open source" are terrible. They're appealing for developers but not the average person. "Photoshop without Adobe's pesky installer" is much better.&lt;/p&gt;

&lt;p&gt;In Signal's case, Edward Snowden had recommended Signal for years. But humans are narrative creatures. We need a story to justify our behaviour. Issues have to be clear and resonate with people. It's not only chanting the merits of your alternative, it's about showing how ugly the status quo is.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UEzFf1Am--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5u9sb55ao2pfmtcte9r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UEzFf1Am--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t5u9sb55ao2pfmtcte9r.png" alt="Comparing the data that various messaging apps link to their users. Signal links no data" width="590" height="339"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WhatsApp was associated with security and privacy, but Facebook wasn't&lt;/strong&gt;. That's what made people quit. The villain of the story became obvious.&lt;/p&gt;

&lt;h3&gt;
  
  
  III. Street credentials
&lt;/h3&gt;

&lt;p&gt;The most discouraging problem with new social apps is "nobody I know uses that." This creates a self-defeating downward spiral that keeps the user base low.&lt;/p&gt;

&lt;p&gt;Signal had just enough notoriety that it wasn't &lt;em&gt;completely&lt;/em&gt; unknown. After Elon Musk's tweet, other &lt;a href="https://twitter.com/KTTunstall/status/1349054688977588224"&gt;celebrities&lt;/a&gt; joined the fun. Signal's founder and CEO was invited on The Joe Rogan Experiment, one of the biggest podcasts in the world.&lt;/p&gt;

&lt;p&gt;As a result of that, Signal became a known quantity. When people asked their friends and families about this "signal thing," someone had heard of it somewhere.&lt;/p&gt;

&lt;h2&gt;
  
  
  What now?
&lt;/h2&gt;

&lt;p&gt;There were multiple factors that contributed towards Signal's success. But the main takeaway is this: Make a great alternative product, and don't compromise.&lt;/p&gt;

&lt;p&gt;If you're an early user of giving feedback about a new app, demand no less than a great UX. Don't worry about the small stuff. Don't nitpick about a feature if most people don't need it.&lt;/p&gt;

&lt;p&gt;If you're a creator/developer, nail the core product, then reach out. I'm as jaded of the marketing logo wall as everyone else, but the beginnings are always tough. I get it, it's easy to forget UX glitches when you're too close to the product. And it's much more fun to work on a coding problem than crafting a compelling marketing message.&lt;/p&gt;

&lt;p&gt;My hope is to see this success is replicated. More competition is better for consumers, well, most of the time. Remember when there was only one TV subscription service?&lt;/p&gt;




&lt;p&gt;Thank you to &lt;a href="https://www.jeremiahlee.com/"&gt;Jeremiah Lee&lt;/a&gt; and &lt;a href="https://kevq.uk/"&gt;Kev Quirk&lt;/a&gt; for reviewing drafts of this article.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>privacy</category>
    </item>
    <item>
      <title>What’s the problem with metadata?</title>
      <dc:creator>Alvin Bryan</dc:creator>
      <pubDate>Mon, 26 Jul 2021 11:41:17 +0000</pubDate>
      <link>https://forem.com/alvinb/what-s-the-problem-with-metadata-2n6k</link>
      <guid>https://forem.com/alvinb/what-s-the-problem-with-metadata-2n6k</guid>
      <description>&lt;p&gt;A friend asked me over the weekend: "What’s wrong with WhatsApp?" &lt;/p&gt;

&lt;p&gt;If messages are encrypted, what’s the big deal? That’s a fair question. The answer reveals a larger problem. The problem with companies (in this case, Facebook) collecting metadata &lt;em&gt;around&lt;/em&gt; your data.&lt;/p&gt;

&lt;p&gt;Let's see why this is dangerous.&lt;/p&gt;

&lt;h2&gt;
  
  
  What’s a metadata anyway?
&lt;/h2&gt;

&lt;p&gt;Data-hungry companies often defend themselves with this misleading statement: "It's OK, it's just metadata."&lt;/p&gt;

&lt;p&gt;Well, what's a metadata? It's data that's about other data. For example: In a chat app, if the message is the primary data, then the metadata could be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The time of the message&lt;/li&gt;
&lt;li&gt;Who you're talking to.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Something like "Ben sends 1 message to Jack today at 18.33"&lt;/p&gt;

&lt;p&gt;It's not OK at all.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why are metadata dangerous?
&lt;/h2&gt;

&lt;p&gt;Metadata collection is harmful to privacy. One single metadata may be harmless, but the more metadata you have, the more complex and precise a picture of you emerges. Let's not forget, metadata come from a variety of sources.&lt;/p&gt;

&lt;p&gt;Let's go back to our example&lt;/p&gt;

&lt;p&gt;"Ben sends 1 message to Mark today at 18.33"&lt;/p&gt;

&lt;p&gt;That's pretty innocuous, right ?&lt;/p&gt;

&lt;p&gt;But when Ben sent the message, WhatsApp (and by extension, Facebook) collected its location. If Ben sent 5 messages over 10 minutes without changing location, Facebook knows Ben isn't moving too much.&lt;/p&gt;

&lt;p&gt;It turns out, Ben is sitting in a waiting room. Waiting to see a discernment counsellor. That's a therapist for people &lt;em&gt;thinking&lt;/em&gt; about divorce. Ben wants to work on himself to save his marriage.&lt;/p&gt;

&lt;p&gt;Facebook knows who Ben is married to already. They know it from an Instagram story of the wedding posted by one of Ben's contacts (even if Ben himself isn't on Instagram).&lt;/p&gt;

&lt;p&gt;Now, from this piece of metadata (his location), Facebook can guess that Ben's marriage isn't doing well.&lt;/p&gt;

&lt;p&gt;Before Ben even left the waiting room, his wife Sarah received an ad&lt;sup id="fnref1"&gt;1&lt;/sup&gt; for a divorce lawyer. 15 minutes later, Sarah sees another ad for a dating app.&lt;/p&gt;

&lt;p&gt;You see, even a series "simple metadata" can reveal a lot about you.&lt;/p&gt;

&lt;p&gt;This is not limited to Facebook. Anyone with metadata about you can run very complex algorithms and profit from it.&lt;/p&gt;

&lt;p&gt;If your bank starts speaking about "sharing data with trusted partners," you should opt-out. Immediately. Now you know how they can make money from your location and card purchases.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Facebook sells information to advertisers everywhere on the Internet, not just on its platform. So Ben's wife can see the ad anywhere on the Internet, even if she's not on Facebook. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>privacy</category>
    </item>
    <item>
      <title>Weak References in JavaScript</title>
      <dc:creator>Alvin Bryan</dc:creator>
      <pubDate>Sun, 03 Jan 2021 11:29:06 +0000</pubDate>
      <link>https://forem.com/alvinb/weak-references-in-javascript-3ni9</link>
      <guid>https://forem.com/alvinb/weak-references-in-javascript-3ni9</guid>
      <description>&lt;p&gt;ES6 introduced &lt;code&gt;WeakMaps&lt;/code&gt; and &lt;code&gt;WeakSets&lt;/code&gt;, which brings weak and strong references to JavaScript, a concept front-enders are not particularly used to.&lt;br&gt;
If you're working on games, you have to pay very close attention to how memory and performance is managed.&lt;/p&gt;

&lt;p&gt;I'm using &lt;code&gt;WeakMap&lt;/code&gt; here as an example, but it's the same for &lt;code&gt;WeakSet&lt;/code&gt; too. The main difference between &lt;code&gt;Map&lt;/code&gt; and &lt;code&gt;Set&lt;/code&gt; is that the latter only keeps unique values.&lt;/p&gt;

&lt;p&gt;According to Wikipedia:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In computer programming, a weak reference is a reference that does not protect the referenced object from collection by a garbage collector, unlike a strong reference.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That actually, surprisingly, makes a lot of sense! Wikipedia got me used to definitions like &lt;code&gt;Coroutines are computer program components that generalize subroutines for non-preemptive multitasking by allowing execution to be suspended and resumed&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Alright, what a &lt;code&gt;WeakMap&lt;/code&gt; does, compared to a good old &lt;code&gt;Map&lt;/code&gt; or &lt;code&gt;{}&lt;/code&gt; is each individual key element in the set can be garbage-collected when they are not referenced somewhere else:&lt;/p&gt;

&lt;p&gt;If this is the content of a regular &lt;code&gt;Map&lt;/code&gt; / &lt;code&gt;{}&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;bigObject&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;spritesheet-1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="cm"&gt;/* gigantic array with a lot of stuff */&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello bla bla&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you're only using it in the code like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spritesheetID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bigObject&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// the gigantic array in myMap.data is in memory&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;em&gt;whole object&lt;/em&gt; and the gigantic array will remain in memory and will &lt;em&gt;not&lt;/em&gt; be CGed until it or its references are destroyed.&lt;/p&gt;

&lt;p&gt;Whereas if you use a weak map anything that isn't being used in your program will be garbage-collected.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// create a WeakMap from the big object&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;weakMap&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;WeakMap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bigObject&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// gigantic array is garbage-collected&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;spritesheetID&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;weakMap&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you could manually &lt;code&gt;delete&lt;/code&gt; the keys of the object that you don't use, but this trick saves you having to keep track of your usage because this isn't C++.&lt;/p&gt;

&lt;p&gt;People have also found other ways to use this with promises and more in &lt;a href="http://stackoverflow.com/questions/29413222/what-are-the-actual-uses-of-es6-weakmap"&gt;this Stackoverflow thread&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That's all for this post! It's a simple concept but needed clarification for me, so I thought I might as well share it.&lt;/p&gt;

&lt;p&gt;Cover Photo by &lt;a href="https://unsplash.com/@thefredyjacob"&gt;Fredy Jacob&lt;/a&gt; on &lt;a href="https://unsplash.com/"&gt;Unsplash&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>programming</category>
      <category>webperf</category>
    </item>
    <item>
      <title>Learn about other commands with `tldr`</title>
      <dc:creator>Alvin Bryan</dc:creator>
      <pubDate>Wed, 25 Nov 2020 12:50:00 +0000</pubDate>
      <link>https://forem.com/alvinb/learn-about-other-commands-with-tldr-1bp6</link>
      <guid>https://forem.com/alvinb/learn-about-other-commands-with-tldr-1bp6</guid>
      <description>&lt;p&gt;There are a few reasons that computer terminals scare people (myself included):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Movie stereotypes of green terminals used by hoodie-wearing hackers in basements.&lt;/li&gt;
&lt;li&gt;How terminals try to “help” you.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The default help pages (called &lt;code&gt;man&lt;/code&gt; pages for manual, go figure) don’t feel designed for humans to me. They’re hard to use and make sense of.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tldr.sh/"&gt;tldr pages&lt;/a&gt; try to fix that. The &lt;code&gt;tldr&lt;/code&gt; utility gives you a people-friendly list of examples to help you with a command.&lt;/p&gt;

&lt;p&gt;Example with the &lt;code&gt;rename&lt;/code&gt; command that we discussed in &lt;a href="https://alvin.codes/writing/nifty-command-lines-rename"&gt;a previous article&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/14d4a5453ce5c2c319c81e0077d8d786/7388e/tldr-rename-console-output.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZX5qX4c7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://alvin.codes/static/14d4a5453ce5c2c319c81e0077d8d786/fcda8/tldr-rename-console-output.png" alt="Console output of tldr pages with the rename command" title="Console output of tldr pages with the rename command" width="590" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Compare that with the &lt;code&gt;man&lt;/code&gt; page, as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RENAME(1) User Contributed Perl Documentation

NAME
       rename - renames multiple files

VERSION
       version 1.600

SYNOPSIS
       rename [switches|transforms] [files]

       Switches:

       -0/--null (when reading from STDIN)
       -f/--force or -i/--interactive (proceed or prompt when overwriting)
       -g/--glob (expand "*" etc. in filenames, useful in WindowsX CMD.EXE)
       -k/--backwards/--reverse-order
       -l/--symlink or -L/--hardlink
       -M/--use=Module
       -n/--just-print/--dry-run
       -N/--counter-format
       -p/--mkpath/--make-dirs
       --stdin/--no-stdin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See how neat this is with &lt;code&gt;ffmpeg&lt;/code&gt;, a tool that’s notoriously unfriendly.&lt;/p&gt;

&lt;p&gt;&lt;a href="///static/7e80259145769ace275d889d38f4c85b/081d5/tldr-ffmpeg-console-output.png"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--D3ND5B25--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://alvin.codes/static/7e80259145769ace275d889d38f4c85b/fcda8/tldr-ffmpeg-console-output.png" alt="FFMPEG Console output" title="FFMPEG Console output" width="590" height="262"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Also, as opposed to &lt;code&gt;man&lt;/code&gt; pages, which require you to install a vim-like interface, tldr pages are easier to contribute to. Everything is in a &lt;a href="https://github.com/tldr-pages/tldr"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, &lt;code&gt;tldr&lt;/code&gt; isn’t limited to the command line. There’s also a &lt;a href="https://marketplace.visualstudio.com/items?itemName=bmuskalla.vscode-tldr"&gt;VSCode Extension&lt;/a&gt;, an &lt;a href="https://github.com/konoui/alfred-tldr"&gt;Alfred Workflow&lt;/a&gt; and even an iOS app.&lt;/p&gt;

&lt;p&gt;If you’re convinced, install it with &lt;code&gt;brew install tldr&lt;/code&gt; on macOS and Linux.&lt;/p&gt;

&lt;p&gt;That’s the end of the series! It introduced you to a few, well, nifty tools that I use quite often, and I hope that it will help you reach out to the terminal to save time.&lt;/p&gt;

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

</description>
      <category>linux</category>
      <category>bash</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Domain records made less weird with `host`</title>
      <dc:creator>Alvin Bryan</dc:creator>
      <pubDate>Mon, 16 Nov 2020 14:09:20 +0000</pubDate>
      <link>https://forem.com/alvinb/nifty-command-lines-host-52k6</link>
      <guid>https://forem.com/alvinb/nifty-command-lines-host-52k6</guid>
      <description>&lt;p&gt;I've been hosting my websites and my domains with different providers for a long time. Same goes for emails. In order to connect your domain to your provider or to your email address, you need do 🚨Domain Verification🚨. And that means doing a few obscure DNS operations like changing name servers and whatnot.&lt;/p&gt;

&lt;p&gt;You set this up on your domain registrar's website. It's usually hidden behind various clunky UIs. Frustrating is an understatement.&lt;/p&gt;

&lt;p&gt;Do you know what the worst part is? After you find the hidden thing, paste the random blob, and sear never to do it again, you can't tell for sure that it worked.&lt;/p&gt;

&lt;p&gt;That's where the &lt;code&gt;host&lt;/code&gt; command comes in. It lets you inspect the DNS records on your domain from your terminal. It probably does other stuff but that's all I ever needed. With this command, you can finally see what your wrangling with the UI did.&lt;/p&gt;

&lt;p&gt;Here are a few examples:&lt;/p&gt;

&lt;p&gt;Show TXT records&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;host &lt;span class="nt"&gt;-t&lt;/span&gt; txt alvin.codes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Show A records&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;host &lt;span class="nt"&gt;-t&lt;/span&gt; a alvin.codes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Show CNAME&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;host &lt;span class="nt"&gt;-t&lt;/span&gt; cname alvin.codes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Show Name Servers&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;host &lt;span class="nt"&gt;-t&lt;/span&gt; ns alvin.codes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;host&lt;/code&gt; command is similar to the &lt;code&gt;dig&lt;/code&gt; command, but it's a lot simpler and easier to remember. I know which one I prefer between typing &lt;code&gt;dig alvin.codes +noall +answer&lt;/code&gt; and &lt;code&gt;host -t a alvin.codes&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bonus: Gitlab &amp;amp; GitHub
&lt;/h2&gt;

&lt;p&gt;Speaking of hidden settings... Here's a bonus for you. Here's what you need to do to connect Gitlab or Github pages to a custom domain.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;For Gitlab&lt;/strong&gt;, 2 things need to be set:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A record set to &lt;code&gt;35.185.44.232&lt;/code&gt;. (Until their IP changes 🤷‍♂️.)&lt;/li&gt;
&lt;li&gt;A TXT record set to &lt;code&gt;gitlab-pages-verification-code=[Your Verification Code]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;For GitHub&lt;/strong&gt; you need to create a &lt;code&gt;CNAME&lt;/code&gt; file at the root of your repository. You can use with the GUI to set it up with the correct values for your domain.&lt;/p&gt;

&lt;p&gt;Then, you need to set the following A records:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="mi"&gt;185&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;199&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;108&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;153&lt;/span&gt;
&lt;span class="mi"&gt;185&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;199&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;109&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;153&lt;/span&gt;
&lt;span class="mi"&gt;185&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;199&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;110&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;153&lt;/span&gt;
&lt;span class="mi"&gt;185&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;199&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;111&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;153&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feel free to reach for this article next time you have a domain to set up, I sure will.&lt;/p&gt;

&lt;p&gt;Good luck,&lt;br&gt;
Alvin&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>bash</category>
      <category>linux</category>
    </item>
    <item>
      <title>Batch-rename files easily with `rename`</title>
      <dc:creator>Alvin Bryan</dc:creator>
      <pubDate>Tue, 27 Oct 2020 11:20:00 +0000</pubDate>
      <link>https://forem.com/alvinb/nifty-command-lines-rename-56oo</link>
      <guid>https://forem.com/alvinb/nifty-command-lines-rename-56oo</guid>
      <description>&lt;p&gt;I use the rename action in macOS Finder when I need simple operations. For example, changing a file extension from &lt;code&gt;.PNG&lt;/code&gt; to &lt;code&gt;.png&lt;/code&gt; or replacing underscores with hyphens. For more complex stuff, like lowercasing, or removing a range of characters, Finder becomes too tedious.&lt;/p&gt;

&lt;p&gt;That’s where the &lt;code&gt;rename&lt;/code&gt; command comes in. It lets you use regular expressions and looks like this: &lt;code&gt;rename -f '[regex]' [files]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Right off the bat, you want to remember the &lt;code&gt;-n&lt;/code&gt; or &lt;code&gt;--dry-run&lt;/code&gt; option. It’s super useful to test out what the resulting files will be without actually renaming them.&lt;/p&gt;

&lt;p&gt;Here’s how you would replace all the double dashes with single ones:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;~/Export ❯❯❯ rename &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s1"&gt;'s/--/-/'&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt;
&lt;span class="s1"&gt;'Example--1.png'&lt;/span&gt; would be renamed to &lt;span class="s1"&gt;'Example-1.png'&lt;/span&gt;
&lt;span class="s1"&gt;'Example--2.png'&lt;/span&gt; would be renamed to &lt;span class="s1"&gt;'Example-2.png'&lt;/span&gt;
&lt;span class="s1"&gt;'Example--3.png'&lt;/span&gt; would be renamed to &lt;span class="s1"&gt;'Example-3.png'&lt;/span&gt;
&lt;span class="s1"&gt;'Example--4.png'&lt;/span&gt; would be renamed to &lt;span class="s1"&gt;'Example-4.png'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;*&lt;/code&gt; in the command above means “do this on all files in the current folder.” You can use glob patterns to specify target files. So, to rename only &lt;code&gt;.png&lt;/code&gt; files, you’d write &lt;code&gt;rename '[regex]' *.png&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As I said, regular expressions.&lt;br&gt;&lt;br&gt;
You write them like this &lt;code&gt;s/[old]/[new]/&lt;/code&gt; or &lt;code&gt;y/[old]/[new]/&lt;/code&gt; without the square brackets.&lt;/p&gt;

&lt;p&gt;In our command, &lt;code&gt;s/&lt;/code&gt; regexes are used for 1-to-1 character mapping while &lt;code&gt;y/&lt;/code&gt; regexes are for more complex replacements involving character ranges. I mostly use &lt;code&gt;y/&lt;/code&gt; regexes because as I said earlier, there’s Finder. Here we go, practical examples.&lt;/p&gt;

&lt;p&gt;Replacing dashes with underscores: &lt;code&gt;rename -f 's/-/_/' *&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It gets really powerful when you can work on character ranges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;rename -f 'y/a-z/A-Z/' *&lt;/code&gt; turns all lowercase into uppercase.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;rename -f 'y/A-Z/a-z/' *&lt;/code&gt; turns all uppercase into lowercase&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More real-world examples.&lt;/p&gt;

&lt;p&gt;Turn filenames into URL-friendly "slugs" 🐌:&lt;br&gt;
&lt;code&gt;rename 'y/A-Z /a-z-/' *&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Remove the &lt;em&gt;last&lt;/em&gt; 𝒙 characters in a filename and replace them:&lt;br&gt;
&lt;code&gt;rename 's/.{𝒙}$/replacement/' *&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In my case, Notion's Markdown export adds 34 random characters to every exported file. That's how I get rid of them:&lt;br&gt;
&lt;code&gt;rename 's/.{36}$/.md/' *.md&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As usual, install it with Homebrew or apt-get: &lt;code&gt;brew install rename&lt;/code&gt; or &lt;code&gt;apt-get install rename&lt;/code&gt;.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>bash</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Show your files and folders with `tree`</title>
      <dc:creator>Alvin Bryan</dc:creator>
      <pubDate>Fri, 23 Oct 2020 12:48:22 +0000</pubDate>
      <link>https://forem.com/alvinb/nifty-command-lines-tree-1j3b</link>
      <guid>https://forem.com/alvinb/nifty-command-lines-tree-1j3b</guid>
      <description>&lt;p&gt;The &lt;code&gt;tree&lt;/code&gt; command is an easy way to print files and folder structures. Like you see in a lot of tutorials. &lt;/p&gt;

&lt;p&gt;Running it without arguments will print your files and folders.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/code-like-the-90s ❯❯❯ tree
.
├── css
│ └── main.css
├── img
│ └── bkg.png
├── index.html
└── script.js

2 directories, 4 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Ignoring
&lt;/h3&gt;

&lt;p&gt;You can tell it to ignore directories with &lt;code&gt;tree -I [DirectoryName]&lt;/code&gt;. In most web scenarios, you’ll want to ignore your npm packages, so &lt;code&gt;tree -I node_modules&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You can exclude more than one folder by separating them with a pipe character.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;tree -I 'node_modules|.cache|test_*|public'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a must to ignore cache folders, build directories, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Restricting output
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;-d&lt;/code&gt; flag restricts it to &lt;em&gt;only&lt;/em&gt; show your folders and hide files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/c/nextjs-app ❯❯❯ tree -d
.
├── pages
│ └── api
├── public
└── styles

4 directories
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-P&lt;/code&gt; flag allows you to only show a certain type of files. For example, if you want to list your JavaScript files while ignoring npm packages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/my-app ❯❯❯ tree -P '*.js' -I 'node_modules'
.
├── public
└── src
    ├── App.js
    ├── App.test.js
    ├── index.js
    ├── serviceWorker.js
    └── setupTests.js

2 directories, 5 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, you can restrict how deep in the folder structure you want to crawl using the &lt;code&gt;-L&lt;/code&gt; flag. &lt;code&gt;tree -L 2&lt;/code&gt; will only go 2 levels deep.&lt;/p&gt;

&lt;p&gt;As usual, install it with Homebrew or apt-get: &lt;code&gt;brew install tree&lt;/code&gt; or &lt;code&gt;apt-get install tree&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There you go! I’ve used this command quite a lot to create documentation or get a sense of a new codebase. I hope it will be useful for you too.&lt;/p&gt;

&lt;p&gt;Cheers&lt;/p&gt;

</description>
      <category>linux</category>
      <category>bash</category>
      <category>productivity</category>
    </item>
    <item>
      <title>Nifty command lines: series intro</title>
      <dc:creator>Alvin Bryan</dc:creator>
      <pubDate>Fri, 23 Oct 2020 12:45:36 +0000</pubDate>
      <link>https://forem.com/alvinb/nifty-command-lines-series-intro-41n3</link>
      <guid>https://forem.com/alvinb/nifty-command-lines-series-intro-41n3</guid>
      <description>&lt;p&gt;I remember when scary terminals became required for web programmers. No more double-clicking &lt;code&gt;index.html&lt;/code&gt;. You had to, &lt;em&gt;gasp&lt;/em&gt;, &lt;strong&gt;run a command&lt;/strong&gt; to work on your website. Who said they miss FTP? Not me…&lt;/p&gt;

&lt;p&gt;I discovered later that the dreaded terminal could do operations that I used random websites for. For instance: Convert a font, a video, etc. While websites work, they can break, start showing NSFW ads, or stop being maintained.&lt;/p&gt;

&lt;p&gt;Command-line interfaces have been around for years (if not decades) without ever changing. Also, it’s easier to remember a command than a bookmark.&lt;/p&gt;

&lt;h3&gt;
  
  
  Housekeeping
&lt;/h3&gt;

&lt;p&gt;I recommend using &lt;a href="https://brew.sh/"&gt;Homebrew&lt;/a&gt; to install your command line tools. It works on macOS, Linux, and Windows using WSL2.&lt;/p&gt;

</description>
      <category>linux</category>
      <category>bash</category>
    </item>
    <item>
      <title>Personal website case study</title>
      <dc:creator>Alvin Bryan</dc:creator>
      <pubDate>Thu, 15 Oct 2020 10:51:43 +0000</pubDate>
      <link>https://forem.com/alvinb/personal-website-case-study-2ahc</link>
      <guid>https://forem.com/alvinb/personal-website-case-study-2ahc</guid>
      <description>&lt;p&gt;I recently launched my personal website. It took a while and was a slog at times, but I learnt a lot along the way. It feels very "me" now.&lt;/p&gt;

&lt;p&gt;The launch day went beyond my expectations. I got lucky that  Josh Comeau liked it enough to &lt;a href="https://twitter.com/JoshWComeau/status/1313124798948663298" rel="noopener noreferrer"&gt;tweet&lt;/a&gt; about it. The numbers were nice, but the most important aspect was the response: People were impressed and genuinely liked it.&lt;/p&gt;

&lt;p&gt;Hopefully folks here will be interested in what's going on under the hood.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requirements&lt;/li&gt;
&lt;li&gt;WebGL&lt;/li&gt;
&lt;li&gt;Gatsby wish list&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Disclaimer: For brevity’s sake I’m assuming a fair bit of prior knowledge. If you would like to learn more about something mentioned here, let me know &lt;a href="https://twitter.com/alvinometric" rel="noopener noreferrer"&gt;on Twitter&lt;/a&gt; or here directly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Minimal tech lock-in&lt;/li&gt;
&lt;li&gt;High lighthouse score (95, at least)&lt;/li&gt;
&lt;li&gt;Try to reduce bundle size as much as possible&lt;/li&gt;
&lt;li&gt;The reading experience works without JavaScript&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Minimal tech lock-in
&lt;/h3&gt;

&lt;p&gt;I don’t want my site to rely on a specific technology too much. I don’t use CSS-in-JS, I hardly use React hooks or component methods, and favour implicit declarations over “Gatsby magic.” Everything should be easy to reproduce with another generator.&lt;/p&gt;

&lt;p&gt;I feel like I made the right choice with Gatsby, and it boils down to two time-saving elements: &lt;em&gt;plugins&lt;/em&gt; and &lt;em&gt;built-ins&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Do you want a dark mode? Here’s &lt;code&gt;gatsby-plugin-dark-mode&lt;/code&gt;. Crazy WebGL graphics with &lt;a href="https://github.com/glslify/glslify" rel="noopener noreferrer"&gt;glslify&lt;/a&gt;? You’ve got &lt;code&gt;gatsby-plugin-glslify&lt;/code&gt;. An RSS feed? Yep. Gatsby even optimises my images, and adds &lt;code&gt;aria-current&lt;/code&gt; to active links.&lt;/p&gt;

&lt;p&gt;On the Markdown side of the house, I dearly missed Jekyll’s fantastic defaults, but again: Plugins! &lt;a href="https://remark.js.org/" rel="noopener noreferrer"&gt;Remark&lt;/a&gt; (the markdown processor) has itself a thriving ecosystem. I got footnotes, custom expanding blocks and table of contents by adding the corresponding plugins.&lt;br&gt;
You can see examples on the original post.&lt;/p&gt;

&lt;p&gt;I’m also pleased that I didn’t have to fiddle with Gatsby internals too much.&lt;/p&gt;

&lt;h3&gt;
  
  
  High Lighthouse score
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0jyl8loun0g7njh9o1kf.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0jyl8loun0g7njh9o1kf.jpeg" alt="Screen shot showing a hight lighthouse score"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is for the homepage that has a WebGL sketch using post-processing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Reduce Bundle size
&lt;/h3&gt;

&lt;p&gt;Throughout the development process of this site I was ruthless when it comes to dependency sizes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I run every dependency through &lt;a href="https://www.npmjs.com/package/package-size" rel="noopener noreferrer"&gt;package-size&lt;/a&gt; to make sure there isn’t a smaller alternative, and including it is weighed against its cost.&lt;/li&gt;
&lt;li&gt;The fonts are compressed as Woff2 files and self-hosted.&lt;/li&gt;
&lt;li&gt;Preact is used to make the Gatsby runtime 30% smaller.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;WebGL sites tend to have needlessly large bundle sizes, here’s my answer to that.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebGL
&lt;/h2&gt;

&lt;p&gt;This site was another excuse to experiment with 3D graphics, shaders and WebGL. Three.js was ruled out from the start because of the &lt;del&gt;ridiculously&lt;/del&gt; large JavaScript size. I tried to strip most features out of Babylon.Js but the bundle was still too big. I ended up using &lt;a href="http://regl.party" rel="noopener noreferrer"&gt;Regl 👑&lt;/a&gt; which is way more lightweight but more low-level, (you have to write GLSL). It’s &lt;a href="https://www.theguardian.com/us-news/ng-interactive/2016/nov/08/us-election-2016-results-live-clinton-trump" rel="noopener noreferrer"&gt;battle-tested&lt;/a&gt;, has been stable for years, and isn’t changing any time soon. Fun fact: Mikola, the creator of Regl, even moved off-the-grid to a lava field at one point and no problem happened with the library.&lt;/p&gt;

&lt;p&gt;I’m keeping an eye on &lt;a href="https://github.com/oframe/ogl" rel="noopener noreferrer"&gt;OGL&lt;/a&gt; which is an even smaller WebGL library and even gives us a scene graph out-of-the-box, but the API isn’t final yet.&lt;/p&gt;

&lt;p&gt;Here’s how they compare (minified size):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;632.33 KB – Three.js v0.120.1&lt;/li&gt;
&lt;li&gt;110.85 KB – Regl v1.6.1&lt;/li&gt;
&lt;li&gt;98.39 KB – OGL v0.0.60&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Picking Regl over Three.js saves us 500kb, more than a &lt;em&gt;five-fold&lt;/em&gt; decrease in bundle size. Performance was also paramount. My goal was a smooth 60fps experience on my old budget Android.&lt;/p&gt;

&lt;p&gt;Thanks to Gatsby’s code-splitting, the WebGL library is &lt;em&gt;only&lt;/em&gt; included in the homepage.&lt;/p&gt;

&lt;h3&gt;
  
  
  Homepage sketch
&lt;/h3&gt;

&lt;p&gt;First, I wanted to create a fractal. They have always fascinated me, whether in code or in nature. There are a lot of fractals to choose from in 2D, but in 3D they’re kind of hard. The only one that I could wrap my head around quickly was the Menger sponge.&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/ac1c4e9671665213134ce281e92d7959/d98c0/menger.jpg"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Falvin.codes%2Fstatic%2Fac1c4e9671665213134ce281e92d7959%2F1c72d%2Fmenger.jpg" title="The 1st homepage sketch: 160 000 cubes forming a Menger sponge fractal" alt="Menger Sponge Fractal"&gt;&lt;/a&gt;The 1st homepage sketch: 160 000 cubes forming a Menger sponge fractal&lt;/p&gt;

&lt;p&gt;After adding a bit of instancing magic, there it was. 60fps and all, except boring to look at. I tucked that code away and turned my attention to another piece of Math &amp;amp; Magic that I had wanted to play with: attractors.&lt;/p&gt;

&lt;p&gt;&lt;a href="/static/7144fb4beaf33553520e28d11b9c6f05/9888a/nose-hoover.jpg"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Falvin.codes%2Fstatic%2F7144fb4beaf33553520e28d11b9c6f05%2F1c72d%2Fnose-hoover.jpg" title="The 2nd homepage sketch: Cubes along a Nosé-Hoover attractor" alt="The Nosé-Hoover Attractor"&gt;&lt;/a&gt;The 2nd homepage sketch: Cubes along a Nosé-Hoover attractor&lt;/p&gt;

&lt;p&gt;Despite running at 60fps it “felt” sluggish and became boring to look at.&lt;/p&gt;

&lt;p&gt;The final attempt at &lt;del&gt;shoehorning&lt;/del&gt; adding 3D graphics to this is what you can see on the homepage now.&lt;/p&gt;

&lt;h2&gt;
  
  
  Gatsby wish list
&lt;/h2&gt;

&lt;p&gt;As with most things in development, there were a few surprises along the way, so here’s my wish list for the Gatsby team:&lt;/p&gt;

&lt;h3&gt;
  
  
  Become evergreen by default
&lt;/h3&gt;

&lt;p&gt;I wish Gatsby’s relationship with older browsers was an “opt-in” one as opposed to “opt-out.” I prefer a lean website out of the box, with features like Webp enabled and polyfills removed by default. I would rather &lt;em&gt;add&lt;/em&gt; backwards compatibility if necessary.&lt;/p&gt;

&lt;h3&gt;
  
  
  Disparity in plugin quality
&lt;/h3&gt;

&lt;p&gt;Gatsby makes it easy to find plugins, and to know which ones are maintained by the core team. Despite this, there is a &lt;em&gt;huge&lt;/em&gt; variance in the quality of the non-official plugins. I wish more things were parsed out of the plugin repository (like the number of open issues without a response) as some are still referenced despite deal-breaker issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Telemetry
&lt;/h3&gt;

&lt;p&gt;That should &lt;strong&gt;&lt;em&gt;absolutely&lt;/em&gt;&lt;/strong&gt; be disabled by default from the stable release.&lt;/p&gt;

&lt;p&gt;I understand the idea, but knowing that a seemingly innocuous CLI might transmit data when I’m not explicitly asking it to is &lt;em&gt;scary&lt;/em&gt;, and sets a dangerous precedent. The logs may be “anonymised” but doing this is &lt;a href="https://protonmail.com/blog/truth-about-anonymized-data/" rel="noopener noreferrer"&gt;extremely&lt;/a&gt; &lt;a href="https://gdpr.eu/data-anonymization-taxa-4x35/" rel="noopener noreferrer"&gt;hard&lt;/a&gt; and a waste of time.&lt;/p&gt;

&lt;p&gt;If it’s not disabled by default, then “How to opt-out of telemetry” should at the very least be part of the kick-start tutorial (like VSCode does) and not &lt;a href="https://www.gatsbyjs.org/docs/telemetry/" rel="noopener noreferrer"&gt;buried&lt;/a&gt; in the documentation. I would even argue that the CLI should ask for again permission every once in a while.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final words
&lt;/h3&gt;

&lt;p&gt;On top of everything mentioned above, I wrote scripts, GraphQL queries, and learned about CSS grids, Exif data, and more. I feel like I’ve come out of it as a better coder.&lt;/p&gt;

</description>
      <category>gatsby</category>
      <category>webgl</category>
      <category>showdev</category>
      <category>blogging</category>
    </item>
  </channel>
</rss>
