<?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: Tony</title>
    <description>The latest articles on Forem by Tony (@tawn33y).</description>
    <link>https://forem.com/tawn33y</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%2F363710%2F77b611c1-9b79-489e-964f-ab82bd26d187.png</url>
      <title>Forem: Tony</title>
      <link>https://forem.com/tawn33y</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tawn33y"/>
    <language>en</language>
    <item>
      <title>One Simple Way To Improve Your Dev.to Experience</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Tue, 16 Feb 2021 11:56:37 +0000</pubDate>
      <link>https://forem.com/tawn33y/one-simple-way-to-improve-your-dev-to-experience-f4o</link>
      <guid>https://forem.com/tawn33y/one-simple-way-to-improve-your-dev-to-experience-f4o</guid>
      <description>&lt;p&gt;A couple of weeks ago, I was almost giving up on Dev.to. I would open the app, scroll through the suggested posts, and sigh in dismay. I couldn't help but think aloud: &lt;strong&gt;My Dev.to feed sucks!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--VBY0DC4U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/722r92xfu4ykbmax3d28.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--VBY0DC4U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/722r92xfu4ykbmax3d28.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My feed was filled with posts of beginner articles in React, JS, etc. I'm not against beginner articles, but when you have read several of these, you can get bored pretty easily with suggestions to read more of the same.&lt;/p&gt;

&lt;p&gt;However, something didn't make sense: I knew that there were people writing posts on advanced/intermediate topics. Why was I then only being shown the beginner topics? Sometimes I was lucky enough to stumble upon such an article, and I'd light up as my interest in the app got renewed. But these were just once-in-a-blue-moon occurrences.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Came Across The Solution By Accident
&lt;/h2&gt;

&lt;p&gt;One evening, I opened the Dev.to app, and I immediately noticed how bright it was, in contrast to my other apps. For some reason, the app did not automatically activate dark mode after sunset. I went exploring in the app settings, and voila! Not only did I find the option to activate dark mode, but also an option to customize my feed.&lt;/p&gt;

&lt;p&gt;Hidden deep in the settings, is a section that asks you your experience level:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2OnKUecx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5hr79qa2kxl7x8l5u5vr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2OnKUecx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5hr79qa2kxl7x8l5u5vr.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can access this via &lt;a href="https://dev.to/settings/customization"&gt;this link&lt;/a&gt;. Just scroll to the bottom.&lt;/p&gt;

&lt;p&gt;By default, no value was selected, and out of curiosity, I updated this to option 5 (Expert), just to see what would happen. I went back to my feed and forgot all about it.&lt;/p&gt;

&lt;p&gt;I didn't notice until much later that my feed had greatly improved. I suddenly wanted to read and save every article on my feed. It only hit me later that the above change had somehow refreshed my feed experience (I guess the cache took a while to update).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZGCZzJZl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uk5evgehqqvl8d21evvs.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZGCZzJZl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/uk5evgehqqvl8d21evvs.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There you have it! If your Dev.to feed sucks, don't despair. Just change your experience level and you will start seeing better content in no time.&lt;/p&gt;

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

&lt;p&gt;PS - it still sucks that there is no auto dark mode to match the device preferences 😩. Dev.to, please do something about it! 😃&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>todayilearned</category>
      <category>devjournal</category>
      <category>meta</category>
    </item>
    <item>
      <title>My Year in Review: 2020</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Tue, 19 Jan 2021 06:15:20 +0000</pubDate>
      <link>https://forem.com/tawn33y/my-year-in-review-2020-10k0</link>
      <guid>https://forem.com/tawn33y/my-year-in-review-2020-10k0</guid>
      <description>&lt;p&gt;In early 2020, I came across Ire Aderinokun's post, &lt;a href="https://medium.com/@ireade/2019-59e4aeb13651"&gt;2019 Year in Review&lt;/a&gt;, and I couldn't help but be in awe of her accomplishments. That year, she had spoken at 4 conferences in multiple locations such as Paris and San Fransisco, traveled to 6 countries, interviewed by the BBC, among several other achievements.&lt;/p&gt;

&lt;p&gt;I was greatly motivated and challenged to achieve my 2020 goals and record them at the year's end. I wrote this just before 2020 ended but I have been holding back on publishing it. Well, here goes...&lt;/p&gt;

&lt;h2&gt;
  
  
  Work Projects
&lt;/h2&gt;

&lt;p&gt;I work at Africa's Talking, a company that provides an API for sending SMS, building USSD apps, and more to 40,000+ devs. You can think of it as the "Twilio of Africa". This year, albeit with the COVID-19 situation and everything going on, we were able to roll out a lot of amazing products/features. A couple of projects I worked on include:&lt;/p&gt;

&lt;h3&gt;
  
  
  a) Product Requests
&lt;/h3&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/W9nAxdwAWlQ"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;I was privileged to solve one of the key challenges we had at work: the creation of a new tool to help customers request a product (e.g. an SMS Sender ID or USSD Service Code) effortlessly and quickly. Previously, to request such a product, you had to send an email to the team stating that you wanted this particular product. The team would then reply, requesting you to send your details, such as your name, contact information, a signed letter authorizing the request, and so much more. Simply put, there would be a lot of back and forth in emails between a customer and the team before a product went live.&lt;/p&gt;

&lt;p&gt;To counter this, we created a feature on the dashboard called &lt;strong&gt;Product Requests&lt;/strong&gt; where users could request the product on their own, upload any documents e.g. signed letters, fill out their information, etc. We also added in a couple of cool features such as a progress bar to show you how far your request was from being completed, a real-time chat feature where users could chat 1-on-1 with the team, and so much more.&lt;/p&gt;

&lt;p&gt;We launched the Beta version in Kenya only, and I have to say, it felt really good to see more than a hundred product requests raised through this and the number of emails substantially going down. We are looking forward to rolling this out to more countries in 2021.&lt;/p&gt;

&lt;h3&gt;
  
  
  b) Africa's Talking Marketplace
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--a0vj_ij5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/i6g9jwv9j3vgpyh0iuh4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--a0vj_ij5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/i6g9jwv9j3vgpyh0iuh4.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PozdxzNm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c292xw64r1b88e0rkloe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PozdxzNm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/c292xw64r1b88e0rkloe.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The Africa's Talking Marketplace is a one-stop-shop platform for users who want a ready-made no-code solution to their problem that makes use of the Africa's Talking API. All products in the Marketplace are created by our customers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;An exciting part about working on this product was using a purely vanilla Typescript implementation, i.e. no React, Vue, Angular, jQuery, etc. I wrote more about this &lt;a href="https://dev.to/tawn33y/2-lessons-learned-from-developing-the-at-marketplace-34h6"&gt;on my blog&lt;/a&gt;. You can also view the actual Marketplace &lt;a href="https://africastalking.com/marketplace"&gt;here&lt;/a&gt;. Impressively, the product received thousands of page visits after we launched 🎉&lt;/p&gt;

&lt;h2&gt;
  
  
  Speaking
&lt;/h2&gt;

&lt;p&gt;One of my 2020 goals was to start speaking at conferences. The problem was, I didn't know how to. Luckily, I met Wayne Rambo, a Software Engineer at Nike, who gave me tons of advice on this. He then introduced me to his friend, Hung Truong, an iOS Engineer at Amazon, who shared with me the basics of conference speaking such as Call For Papers (CFPs) and more. Finally, I spoke to my work colleague, Anthony Kiplimo, about my desire to speak at conferences and he made sure to tag me along in the events he would speak at.&lt;/p&gt;

&lt;p&gt;I mention these three people because I'm particularly grateful to them. Without them, I never would have been able to speak at the 4 events/conferences I spoke at this year, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Build for SDG Challenge 2020&lt;/strong&gt;: a Facebook/Andela immersive program where participants innovate in industry-led projects or SDGs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PhRX3s9I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jwy2d46ky7cn9dr58972.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PhRX3s9I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jwy2d46ky7cn9dr58972.png" alt="Build for SDG Challenge 2020"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Africa Digital Skills Conference&lt;/strong&gt;: an Africa-wide conference to teach digital skills.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SrMWK9X0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7v0e9aazr44ub0b85eba.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SrMWK9X0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/7v0e9aazr44ub0b85eba.png" alt="Africa Digital Skills Conference"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DSC KU&lt;/strong&gt;: Developer Students Club, Kenyatta University&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jB4VDzsZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ihvl9ug8pysrwieigpij.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jB4VDzsZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/ihvl9ug8pysrwieigpij.png" alt="DSC KU"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DSC Moi University&lt;/strong&gt;: Developer Students Club, Moi University&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--taVWqr0u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d3kpbithuufzfy5t2lkx.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--taVWqr0u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/d3kpbithuufzfy5t2lkx.jpeg" alt="DSC Moi University"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Events
&lt;/h2&gt;

&lt;p&gt;Apart from speaking at events, I also attended several events. Although a pandemic, the COVID-19 brought along one advantage: virtual events; events that I otherwise would never have had the opportunity to attend. My top favorites were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;React Summit&lt;/strong&gt;: to say that this was fun is an understatement 😃&lt;/li&gt;
&lt;/ul&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--y9hoXcJ1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/EWCzFINXkAIj0gl.jpg" alt="unknown tweet media content"&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--3h-ATRvd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1267506899882258433/9bPC3iHc_normal.jpg" alt="Tony profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Tony
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/tawn33y"&gt;@tawn33y&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      I just saw &lt;a href="https://twitter.com/VladimirNovick"&gt;@VladimirNovick&lt;/a&gt; use his mind to interact with a web page and fly a drone 🤯&lt;br&gt;&lt;a href="https://twitter.com/hashtag/ReactSummit"&gt;#ReactSummit&lt;/a&gt; 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      11:29 AM - 20 Apr 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1252197735740121090" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1252197735740121090" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1252197735740121090" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;
&lt;br&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qeLRrg_7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/EWCz82fWAAQw3Tv.jpg" alt="unknown tweet media content"&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--3h-ATRvd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1267506899882258433/9bPC3iHc_normal.jpg" alt="Tony profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Tony
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/tawn33y"&gt;@tawn33y&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      I had tons of fun at &lt;a href="https://twitter.com/hashtag/ReactSummit"&gt;#ReactSummit&lt;/a&gt; 🎉&lt;br&gt;Thank you &lt;a href="https://twitter.com/ReactAmsterdam"&gt;@ReactAmsterdam&lt;/a&gt;, all the speakers, and everyone involved! 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      11:33 AM - 20 Apr 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1252198797448445953" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1252198797448445953" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1252198797448445953" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ByteConf React 2020&lt;/strong&gt;: I think I attended this event just to hear Kent C Dodds speak 😃&lt;/li&gt;
&lt;/ul&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7GvEQn_9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/EW8jZwVWkAIt1bZ.jpg" alt="unknown tweet media content"&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--3h-ATRvd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1267506899882258433/9bPC3iHc_normal.jpg" alt="Tony profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Tony
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        &lt;a class="mentioned-user" href="https://dev.to/tawn33y"&gt;@tawn33y&lt;/a&gt;

      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      &lt;a href="https://twitter.com/hashtag/ByteConf"&gt;#ByteConf&lt;/a&gt; is finally here!! 🎉&lt;br&gt;&lt;br&gt;Link: &lt;a href="https://t.co/yhOw67CxCz"&gt;youtube.com/watch?v=MEeZLM…&lt;/a&gt; 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      16:39 PM - 01 May 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1256261987245441024" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1256261987245441024" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1256261987245441024" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Github Universe&lt;/strong&gt;: I still think that Github's Dark Mode unveiling is the coolest dark-mode launch ever! 💯&lt;/li&gt;
&lt;/ul&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;
      &lt;div class="ltag__twitter-tweet__media ltag__twitter-tweet__media__video-wrapper"&gt;
        &lt;div class="ltag__twitter-tweet__media--video-preview"&gt;
          &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2tq_hJsc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/media/Eou2xafWMAEYawo.jpg" alt="unknown tweet media content"&gt;
          &lt;img src="/assets/play-butt.svg" class="ltag__twitter-tweet__play-butt" alt="Play butt"&gt;
        &lt;/div&gt;
        &lt;div class="ltag__twitter-tweet__video"&gt;
          
            
          
        &lt;/div&gt;
      &lt;/div&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--1ade2nZ6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/1338344493234286592/C_ujKIUa_normal.png" alt="GitHub profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        GitHub
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @github
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      echo "hello, darkness" &lt;a href="https://twitter.com/hashtag/GitHubUniverse"&gt;#GitHubUniverse&lt;/a&gt; &lt;a href="https://twitter.com/hashtag/Keynote"&gt;#Keynote&lt;/a&gt; &lt;a href="https://t.co/9gQRFt3aqQ"&gt;githubuniverse.com&lt;/a&gt; 
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      17:31 PM - 08 Dec 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1336362679506784256" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1336362679506784256" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1336362679506784256" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  Learning
&lt;/h2&gt;

&lt;p&gt;This year, I mainly learned 4 new tools: GraphQL, Tailwind CSS, Figma, and Kubernetes (I'm still a beginner though!).&lt;/p&gt;

&lt;h2&gt;
  
  
  Other Achievements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;GADS 2020&lt;/strong&gt;: I was privileged to be a mentor at &lt;a href="https://gads.andela.com"&gt;Google Africa Developers Scholarship 2020&lt;/a&gt;, a learning program offering free Pluralsight access to 30,000+ learners.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Code Hub&lt;/strong&gt;: my &lt;a href="https://t.me/code_hub"&gt;telegram channel&lt;/a&gt; surpassed 500 members 🥳️&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;YouTube tutorial&lt;/strong&gt;: my &lt;a href="https://www.youtube.com/watch?v=DW8Wqnc5_I8"&gt;first YouTube tutorial&lt;/a&gt; garnered 800+ views 🎉&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Blog post&lt;/strong&gt;: I received the highest number of views on any of my blog posts ever, after &lt;a href="https://dev.to/tawn33y/2-quick-tips-when-working-with-js-console-output-4hjo"&gt;one of my blog posts&lt;/a&gt; got 600+ visitors in less than 24 hours 🙌&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open Source&lt;/strong&gt;: I only worked on one open-source initiative this year, url-to-markdown: a fast way to convert a Medium blog article into markdown. I created this since &lt;a href="http://heckyesmarkdown.com"&gt;heckyesmarkdown.com&lt;/a&gt; was not working at the time, but I have since taken it down.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Personal - hiking
&lt;/h2&gt;

&lt;p&gt;I was more serious about hiking this year and hiked several places such as Mt. Longonot (~13kms), Ngong Hills (~16kms), Karura Forest (~16kms), and more. Here's to more hiking in 2021! 🥳️&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w2g4BtXI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tzja4s7y9caph84keit8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w2g4BtXI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/tzja4s7y9caph84keit8.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--n4FjrPkq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lujjqkqt8cjgqqpx3l2j.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--n4FjrPkq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lujjqkqt8cjgqqpx3l2j.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What about 2021?
&lt;/h2&gt;

&lt;p&gt;I can't wait to see what 2021 brings. One thing I certainly would like to work on this year is building more open-source projects, something I wasn't able to do last year. For now, I'm just thankful to God for everything I achieved in 2020. See you soon!&lt;/p&gt;

</description>
      <category>career</category>
      <category>devjournal</category>
      <category>yearinreview</category>
      <category>javascript</category>
    </item>
    <item>
      <title>2 Quick Tips when working with JS console output</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Wed, 23 Sep 2020 07:54:44 +0000</pubDate>
      <link>https://forem.com/tawn33y/2-quick-tips-when-working-with-js-console-output-4hjo</link>
      <guid>https://forem.com/tawn33y/2-quick-tips-when-working-with-js-console-output-4hjo</guid>
      <description>&lt;p&gt;Here are 2 quick tips you can use when working with the output from JS console:&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Displaying data
&lt;/h2&gt;

&lt;p&gt;If you are displaying arrays or objects, use &lt;code&gt;console.table&lt;/code&gt; rather than &lt;code&gt;console.log&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="c1"&gt;// try running this:&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;table&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;John&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Doe&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;William&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Shakespeare&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;age&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will display the data in a nice tabular view as shown below:&lt;/p&gt;

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

&lt;h2&gt;
  
  
  2) Copying data
&lt;/h2&gt;

&lt;p&gt;If you are working with Google Chrome &amp;amp; need to copy data from the console output, instead of manually highlighting &amp;amp; copying the data, you can run 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;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="nf"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will copy the data to your clipboard.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt;: the &lt;code&gt;copy&lt;/code&gt; command is only available on Chrome &amp;amp; not on the node.js env.&lt;/p&gt;




&lt;p&gt;Have fun coding! 🎉&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>webdev</category>
      <category>node</category>
    </item>
    <item>
      <title>2 Lessons learned from developing the AT Marketplace</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Mon, 13 Jul 2020 23:00:10 +0000</pubDate>
      <link>https://forem.com/tawn33y/2-lessons-learned-from-developing-the-at-marketplace-34h6</link>
      <guid>https://forem.com/tawn33y/2-lessons-learned-from-developing-the-at-marketplace-34h6</guid>
      <description>&lt;p&gt;One of my babies just went live! 🎉😃&lt;/p&gt;

&lt;p&gt;The AT Marketplace is a tool that showcases great applications or services that have been created by businesses or developers using Africa’s Talking APIs. You can &lt;a href="https://africastalking.com/marketplace"&gt;view it here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I had lots of fun working on this - for the first time in a long while, I opted out of using React/Vue/Angular/jQuery, and instead, just wrote vanilla Typescript. I couldn't help but have nostalgic feelings as I remembered the good ol' days when I was starting out as a developer and all I knew was jQuery or simple Javascript.&lt;/p&gt;

&lt;p&gt;Of course, I could not have done this alone. The many code and UI reviews by my colleagues  Calvin, Raj and Matt were quite fundamental in achieving the final output, and echo deeply of the priceless value of teamwork in projects.&lt;/p&gt;

&lt;p&gt;I will share two core concepts used in the app, that I most certainly did not know as a newbie:&lt;/p&gt;

&lt;h2&gt;
  
  
  1) Immutability
&lt;/h2&gt;

&lt;p&gt;Immutability means unable to change: once you initialize a value, you should never change its state, e.g. if the name of a person is John, you should never ever rename that name to Mary or something else.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gJU2AVHQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vxrdnl89d56yh20o7cw5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gJU2AVHQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vxrdnl89d56yh20o7cw5.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm an astute lover of immutability and I apply it anytime I code, but I will be honest: I have never grasped its other side till most recently. For example, on the Marketplace, I first set it up to display all listings, then react to events: if a user searched for a listing, I would loop through the currently displayed listings and hide all the ones that did not match the search query. I would apply the same principle when a user selected a filter (e.g. Kenya, SMS).&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;filteredListings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;filterListings&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// some logic to search or filter&lt;/span&gt;

&lt;span class="nx"&gt;filteredListings&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`listing_&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="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;style&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;none&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;This changed as I grasped the other side of immutability when playing around with Kubernetes: once you build an image and you need to do some changes, you never edit the existing image; rather, you always build a new image and then deploy this newer image. I achieved this in the Marketplace by separating data logic from the UI. Now, if you search for a listing on the page, there is no looping to hide/show listings; rather, a new UI is built afresh using the new data and then this new UI is inserted into the DOM to replace the existing one. &lt;em&gt;This is so subtle and happens so fast that there is no screen freezing/loading.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createMutableState&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mutablestate.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;listings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createMutableState&lt;/span&gt;&lt;span class="p"&gt;([]);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;handleSearch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// some logic to search&lt;/span&gt;

        &lt;span class="nx"&gt;listings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filteredListings&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="nx"&gt;listings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onChange&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// regenerate html&lt;/span&gt;

        &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;innerHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;html&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The library used above is a small library I created a while back. &lt;a href="https://www.npmjs.com/package/mutablestate.js"&gt;You can check it out here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The effect was instant: the code became a lot cleaner and easier to read and test. Search and filter functions do just that: they search/filter the data, and are never concerned with updating the UI. Also, this helps the app adhere to one of the golden rules: &lt;em&gt;never trust data attributes parsed from HTML.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Was this paradigm shift beneficial? I'll let you be the judge: for Marketplace, it reduced the amount of code by about 72% - e.g. there is only one 'document.getElementById' compared to about 20 or so before.&lt;/p&gt;

&lt;p&gt;Unfortunately or fortunately, nowadays this is done for developers inside frameworks such as React that many of us don't really know how it happens. e.g. for React, we just know the theory: updates are done on the virtual DOM, a diff is calculated between this and the actual DOM, and then the diff is used to update the actual DOM.&lt;/p&gt;

&lt;p&gt;But I have to say: getting my hands dirty gave me a fresh perspective on the differences of MV*, how to build your own useState and useEffect, among several other things. Understanding the inner workings also helped me gain a lot more respect for React as a framework.&lt;/p&gt;

&lt;h2&gt;
  
  
  2) Optimistic updates
&lt;/h2&gt;

&lt;p&gt;There are several use-cases of this but I will focus on one example: you might have seen this in your phone applications: when you open Whatsapp, you never see a loading image; rather you see old messages, which are then updated as new messages start streaming in.&lt;/p&gt;

&lt;p&gt;For Marketplace, when you first load the page, data is retrieved from the API and then cached. If you refresh the page or view one of the listings, data is fetched from the cache instead of the API so that the page loads much faster and you don't see a loading icon; then in the background, an API call is made to check if there are any changes to the data, and if there are, the UI is updated accordingly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fK-tUFFf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vwxjdtnpt8ypmua7evfb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fK-tUFFf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vwxjdtnpt8ypmua7evfb.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Last Word
&lt;/h2&gt;

&lt;p&gt;I hope you learnt a thing or two from our experiences. If you are a dev newbie, I challenge you not to &lt;em&gt;just&lt;/em&gt; use React or Vue or [insert framework here]. Teach yourself how to write apps in your free time using plain JS: it will really help you grow as a developer.&lt;/p&gt;

&lt;p&gt;Till next time, stay safe! 👋&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>ux</category>
      <category>react</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A free utility for easy routing in USSD applications</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Mon, 20 Apr 2020 10:16:59 +0000</pubDate>
      <link>https://forem.com/tawn33y/a-free-utility-for-easy-routing-in-ussd-applications-3b6j</link>
      <guid>https://forem.com/tawn33y/a-free-utility-for-easy-routing-in-ussd-applications-3b6j</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;TL;DR Use the ussd-router utility to manage USSD routing headaches. &lt;a href="https://www.npmjs.com/package/ussd-router"&gt;Install on npm&lt;/a&gt; or &lt;a href="https://github.com/tawn33y/ussd-router/blob/master/src/index.ts"&gt;view the source code&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Case Study: The headache in building USSD apps
&lt;/h2&gt;

&lt;p&gt;Imagine you are building a USSD application as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AZdcC5uW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fcjfr2qi1ulks6ayjfwg.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AZdcC5uW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fcjfr2qi1ulks6ayjfwg.jpeg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perhaps, you would write code as follows:&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;bodyParser&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;body-parser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;port&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bodyParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;urlencoded&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;extended&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/webhook/ussd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;footer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;0: Back 00: Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1: Buy data bundles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;2: Buy calls and sms bundles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1: Daily bundles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;2: Weekly bundles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1*1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1. Buy for my number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;2. Buy for other number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// more logic&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;port&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Server running...&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;The important part is in the &lt;em&gt;if-else&lt;/em&gt; flow, which allows you to add several screens to the USSD application:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This works flawlessly! But what happens when a user decides to navigate to the previous screen by pressing ‘0’ or to the home screen by pressing ‘00’?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You guessed it. This introduces an unsavory chain of &lt;em&gt;if-else&lt;/em&gt; statements:&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;footer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;0: Back 00: Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawText&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;rawText&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1*00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;rawText&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1*0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;rawText&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1*1*00&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1: Buy data bundles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;2: Buy calls and sms bundles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawText&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;rawText&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1*1*0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1: Daily bundles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;2: Weekly bundles&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;footer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawText&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1*1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;rawText&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1*1*1*0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1: Buy for my number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;2: Buy for other number&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="nx"&gt;footer&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;Ugh. That’s one huge spaghetti of code.&lt;/p&gt;

&lt;p&gt;Mind you, I didn’t even explore all the paths a user could take while navigating. In fact, as the user navigates deeper and deeper and decides to navigate to the previous/home screen, it may get too complicated for you to even handle the logic.&lt;/p&gt;

&lt;h2&gt;
  
  
  The solution
&lt;/h2&gt;

&lt;p&gt;As illustrated, you may decide to handle the routing on your own, but that will add unnecessary boilerplate to your code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Or you could use the &lt;code&gt;ussd-router&lt;/code&gt; library.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;ussd-router&lt;/code&gt; library will help you remove the boilerplate needed to handle navigation in your application to the previous/home screen, and let you rest easy as you concentrate on your business logic.&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ussdRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ussd-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ussdRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;544*1*2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// '544*1*2'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ussdRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;544*1*2*00*3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// '544*1*3'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ussdRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;544*1*2*0*1*2&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// '1*2'&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ussdRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;544*1*2*0*1*2*00*3&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// '1*3'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Thus, you can update your code as follows:&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="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;ussdRouter&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ussd-router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/webhook/ussd&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;rawText&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ussdRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;msg&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// do something&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// do something else&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 never again have to worry about handling navigation in your USSD application.&lt;/p&gt;

&lt;h2&gt;
  
  
  What if I want to use a different keyword to go to the home/previous screen?
&lt;/h2&gt;

&lt;p&gt;By default  &lt;code&gt;0&lt;/code&gt; is the keyword used to go to the home screen, while &lt;code&gt;00&lt;/code&gt; is used to go to the previous screen.&lt;/p&gt;

&lt;p&gt;If you want to change this, simply update this as follows:&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;text1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;ussdRouter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rawText&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;98&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;99&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;Here, &lt;code&gt;98&lt;/code&gt; is the keyword that will be used to go to the home screen, while &lt;code&gt;99&lt;/code&gt; will be used to go to the previous screen.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting the library
&lt;/h2&gt;

&lt;p&gt;If you use node.js, you can &lt;a href="https://www.npmjs.com/package/ussd-router"&gt;install the npm package&lt;/a&gt; as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i ussd-router
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don’t use node.js, you can view the &lt;a href="https://github.com/tawn33y/ussd-router/blob/master/src/index.ts"&gt;source code&lt;/a&gt;, and transpile the algorithm into the programming language of your choice.&lt;/p&gt;

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

&lt;h3&gt;
  
  
  Want to get started on building USSD apps today? Visit &lt;a href="http://africastalking.com/"&gt;https://africastalking.com/&lt;/a&gt;
&lt;/h3&gt;

</description>
      <category>node</category>
      <category>javascript</category>
      <category>ussd</category>
      <category>africastalking</category>
    </item>
    <item>
      <title>Here’s a reason why your website is not secure</title>
      <dc:creator>Tony</dc:creator>
      <pubDate>Thu, 09 Apr 2020 18:18:51 +0000</pubDate>
      <link>https://forem.com/tawn33y/here-s-a-reason-why-your-website-is-not-secure-1no1</link>
      <guid>https://forem.com/tawn33y/here-s-a-reason-why-your-website-is-not-secure-1no1</guid>
      <description>&lt;p&gt;If you are a website developer, you have most probably protected yourself from common attacks such as XSS, SQL, CSRF, etc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;But are you safe from a Clickjacking attack?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Try this:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;1) Create a blank html file&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;2) Add the following code:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;style&amp;gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;iframe&lt;/span&gt; &lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;”http://your-site.com"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;”100%”&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;”100%”&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;”border:&lt;/span&gt; &lt;span class="err"&gt;0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then open the html file in your browser. If your browser loads your website, congratulations (&lt;em&gt;pun&lt;/em&gt;)! You’re susceptible to &lt;em&gt;clickjacking attacks&lt;/em&gt; :)&lt;/p&gt;

&lt;p&gt;But if your browser displays the following error (or similar) in your console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Refused to display ‘https://your-site.com' in a frame because it set ‘X-Frame-Options’ to ‘sameorigin’.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then you are &lt;em&gt;[relatively]&lt;/em&gt; safe.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;What is Clickjacking?&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Clickjacking is an attack where an attacker uses an iframe to load your site and tricks a user to click on a button/link. The attacker then hijacks the clicks meant for the original server.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The above code opens your website in such a way that no one can tell the difference between your real website and the iframed version, especially if an attacker uses a [false] url &lt;em&gt;similar&lt;/em&gt; to your domain name, e.g. &lt;em&gt;faceebook.com&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most sites like Facebook, Github, Whatsapp, etc have blocked iframes page loading, i.e. you cannot load any of these pages via an iframe. YouTube only allows embedded videos.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Whether you are using Nginx, Apache server, etc., you should disable the loading of your website in an iframe by setting the &lt;code&gt;x-frame-options&lt;/code&gt; header in your config files to DENY, e.g.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;x-frame-options: DENY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Protect yourself from Clickjacking attacks today.&lt;/p&gt;

&lt;p&gt;You can learn more here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://keycdn.com/blog/x-frame-options"&gt;https://keycdn.com/blog/x-frame-options&lt;/a&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>javascript</category>
      <category>html</category>
      <category>clickjacking</category>
    </item>
  </channel>
</rss>
