<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:googleplay="http://www.google.com/schemas/play-podcasts/1.0"><channel><title><![CDATA[Coderbased]]></title><description><![CDATA[A Software Engineering newsletter to help you become a hands-on tech leader. Every week, we write about system design, leadership, mindset, and tips to become a better software engineer.]]></description><link>https://www.coderbased.com</link><image><url>https://substackcdn.com/image/fetch/$s_!fzUJ!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F08432283-5478-4eaa-b7c0-21d3acf55c1e_512x512.png</url><title>Coderbased</title><link>https://www.coderbased.com</link></image><generator>Substack</generator><lastBuildDate>Wed, 29 Apr 2026 23:16:51 GMT</lastBuildDate><atom:link href="https://www.coderbased.com/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Herry Gunawan]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[coderbased@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[coderbased@substack.com]]></itunes:email><itunes:name><![CDATA[Herry Gunawan]]></itunes:name></itunes:owner><itunes:author><![CDATA[Herry Gunawan]]></itunes:author><googleplay:owner><![CDATA[coderbased@substack.com]]></googleplay:owner><googleplay:email><![CDATA[coderbased@substack.com]]></googleplay:email><googleplay:author><![CDATA[Herry Gunawan]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[The 4 Communication Styles of Software Engineers]]></title><description><![CDATA[Understanding the 4 communication styles in software engineers&#8212;driver, analytical, amiable, and expressive&#8212;and how to handle and influence them]]></description><link>https://www.coderbased.com/p/the-4-communication-styles-of-software</link><guid isPermaLink="false">https://www.coderbased.com/p/the-4-communication-styles-of-software</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Mon, 14 Oct 2024 08:01:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e7e99f85-834d-4910-8409-9e3861928115_1280x720.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to Coderbased, a software engineering newsletter that helps you to become hands on tech leader. Every week we write about system design, leadership, software engineering mindset or tips to become better Software Engineer.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.linkedin.com/in/herryg91">Linkedin</a>, <a href="https://twitter.com/herryg91">Twitter</a> and share this content to your friends. Enjoy.</p></blockquote><p>Many software engineers struggle with communication skills, but effective communication is crucial in our field. Strong communication abilities can enhance collaboration, streamline work processes, and even help promote your contributions, leading to recognition and potential promotions.</p><p>To begin improving your communication, it's essential to understand the communication styles of your peers and fellow software engineers. Recognizing these styles can significantly <strong>improve your relationships, performance, and job satisfaction.</strong> This knowledge has opened my perspective on effective communication and helped me identify the right team members for specific roles.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Coderbased! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><p>Here are the four main communication styles commonly found among software engineers:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Pwzt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cef003-83c4-44ad-8a58-ff3427a044bf_1394x1164.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Pwzt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cef003-83c4-44ad-8a58-ff3427a044bf_1394x1164.png 424w, https://substackcdn.com/image/fetch/$s_!Pwzt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cef003-83c4-44ad-8a58-ff3427a044bf_1394x1164.png 848w, https://substackcdn.com/image/fetch/$s_!Pwzt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cef003-83c4-44ad-8a58-ff3427a044bf_1394x1164.png 1272w, https://substackcdn.com/image/fetch/$s_!Pwzt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cef003-83c4-44ad-8a58-ff3427a044bf_1394x1164.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Pwzt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cef003-83c4-44ad-8a58-ff3427a044bf_1394x1164.png" width="500" height="417.5035868005739" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/31cef003-83c4-44ad-8a58-ff3427a044bf_1394x1164.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1164,&quot;width&quot;:1394,&quot;resizeWidth&quot;:500,&quot;bytes&quot;:2135994,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Pwzt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cef003-83c4-44ad-8a58-ff3427a044bf_1394x1164.png 424w, https://substackcdn.com/image/fetch/$s_!Pwzt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cef003-83c4-44ad-8a58-ff3427a044bf_1394x1164.png 848w, https://substackcdn.com/image/fetch/$s_!Pwzt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cef003-83c4-44ad-8a58-ff3427a044bf_1394x1164.png 1272w, https://substackcdn.com/image/fetch/$s_!Pwzt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F31cef003-83c4-44ad-8a58-ff3427a044bf_1394x1164.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>1. Driver Software Engineer</h3><p>Achiever - Quick - Direct - Competitive</p><p>Driver engineers focus on problem-solving and making quick decisions to achieve clear goals efficiently. They generate ideas rapidly and prefer direct communication. Driven by results, they prioritize tasks based on impact and often push themselves and others to meet tight deadlines. Their strong personalities tend to lead them to take charge and expect others to follow.</p><p>While they excel in roles where decisiveness and action are valued, they may have little patience for unnecessary discussions or delays. This focus on swift results can sometimes strain relationships with team members who prefer more collaborative or thoughtful discussions, especially if they feel rushed or undervalued.</p><p><strong>How to communicate with Driver Software Engineers:</strong></p><p>Be direct and concise, focusing on clear outcomes and how your proposal will help achieve their goals quickly. Avoid unnecessary details and emphasize tangible benefits, such as increased efficiency or faster results. If they are insistent on their ideas, respect their need for autonomy and allow them the space to make decisions without micromanagement. It&#8217;s wise to prepare backup plans in case things don&#8217;t go as expected. Fortunately, driver types often learn quickly from failures.</p><h3>2. Analytical Software Engineer</h3><p>Detail - Structural - Data Driven - Cautious</p><p>Analytical engineers are also focused on solving problems, but they tend to seek out information, ask questions, and gather details before making plans or decisions. They are methodical, detail-oriented, and highly focused on logic and accuracy. Analytical engineers thrive on data collection and analysis, approaching problems systematically. They prefer to work at a slower, more deliberate pace, ensuring they fully understand a problem before developing a solution. Their meticulous nature often leads them to evaluate all possible options, identify potential risks, and consider long-term outcomes.</p><p>However, their desire for thoroughness can lead to "analysis paralysis," causing delays in decision-making and project progress. They may become so caught up in perfecting details or exploring multiple solutions that it slows down the workflow.</p><p><strong>How to communicate with Analytical Software Engineers:</strong></p><p>Be detailed, logical, and well-prepared. Present facts, data, and clear evidence to support your points, as they value accuracy and thoroughness. Ensure your arguments are well-founded and can be substantiated. Be patient and give them time to analyze information before making decisions. Additionally, structure your discussions by breaking down complex topics into clear, logical steps, and be ready to answer their questions, as they often seek clarification.</p><h3>3. Amiable Software Engineer</h3><p>Democracy - Empathetic - Conflict Avoid - Supportive</p><p>Amiable engineers are empathetic, approachable, and thrive in collaborative environments. They often prioritize harmony and positive interactions within the team. In simple terms, they want everyone to be happy. Amiable engineers are great listeners and supportive of others, making them effective at mediating conflicts and fostering a positive work culture. When issues arise, they may hesitate to share their ideas until they feel comfortable with the situation. They value consensus and input from others before making decisions.</p><p>While they excel in building strong, trusting relationships, their focus on maintaining harmony can sometimes lead them to avoid difficult conversations or necessary confrontations. This tendency may slow down decision-making and lead to unresolved issues. Additionally, their desire to please others can make them reluctant to push back on unreasonable demands or tight deadlines, potentially resulting in overcommitting and blurred boundaries.</p><p><strong>How to communicate with Amiable Software Engineers:</strong></p><p>Avoid exploiting their kindness by taking on the "bad cop" role. Instead, create a collaborative environment by inviting them to work together. Establish a friendly tone and show genuine interest in their thoughts and feelings. Encourage open dialogue and actively listen to their concerns, ensuring they feel heard and valued. When discussing projects or ideas, frame your suggestions around teamwork and shared goals, as they appreciate collaboration. Be patient and steer clear of aggressive communication styles that may make them uncomfortable. Recognize their contributions and create space for them to express their opinions without pressure.</p><h3>4. Expressive Software Engineer</h3><p>Creative - Big Picture - Spontaneous - Optimistic</p><p>Expressive engineers enjoy engaging discussions, brainstorming, and collaborating with others. They thrive in dynamic environments and are typically outgoing, easily connecting with their peers. Expressive engineers are effective at inspiring and motivating team members, often thinking outside the box and exploring innovative solutions. However, they may prefer a faster-paced work environment, which can lead to a focus on ideas rather than practical execution. While they enjoy collaboration, they might need reminders to stay on task and follow through with their concepts.</p><p>Their emphasis on creativity and enthusiasm can sometimes result in a lack of attention to detail or practical implementation, affecting project timelines. They often generate many ideas but may struggle to maintain focus during the execution phase.</p><p><strong>How to communicate with Expressive Software Engineers:</strong></p><p>Create an engaging and open environment that encourages idea sharing. Start by showing enthusiasm for their thoughts and contributions, as they thrive on positive reinforcement. Use an interactive approach during discussions, allowing them to express their creativity while keeping the conversation focused. Help them structure and summarize the discussion. Provide clear goals and deadlines to keep them on track while allowing flexibility for their creative input. Lastly, be patient and ready to clarify points, as their expressive nature might lead to fast-paced exchanges that require further explanation.</p><div><hr></div><p>These are the four communication styles. While each person may exhibit a dominant style, many may also combine two or more styles. Personally, I identify most with the analytical style. What about you? Share your thoughts in the poll below!</p><div class="poll-embed" data-attrs="{&quot;id&quot;:223637}" data-component-name="PollToDOM"></div><p></p>]]></content:encoded></item><item><title><![CDATA[Custom Domain System Design]]></title><description><![CDATA[Create a custom domain system design using multi-tenant system architecture with an SQL database.]]></description><link>https://www.coderbased.com/p/custom-domain-system-design</link><guid isPermaLink="false">https://www.coderbased.com/p/custom-domain-system-design</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Thu, 10 Oct 2024 12:02:01 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/fe89d8e2-6e17-4f96-b423-3f6595fecd3d_1280x720.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to Coderbased, a software engineering newsletter that helps you to become hands on tech leader. Every week we write about system design, leadership, software engineering mindset, tips to become better Software Engineer.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.linkedin.com/in/herryg91">Linkedin</a>, <a href="https://twitter.com/herryg91">Twitter</a> and share this content to your friends. Enjoy.</p></blockquote><p>The <strong>custom domain feature</strong> enables you to use your own domain to access a service, even though, behind the scenes, it&#8217;s actually hosted by another service. This feature is commonly offered by SaaS platforms or B2B white-label solutions.</p><p>For a simple example, although you're accessing this website through <strong>coderbased.com</strong>, it&#8217;s actually hosted on Substack. Initially, the domain was <strong>coderbased.substack.com</strong>, provided when we registered our publisher account.</p><p>Today, we&#8217;re going to discuss how to design a system for a custom domain feature. This is an exciting topic, so let&#8217;s dive in.</p><h2>Building a Custom Domain Feature</h2><p>Imagine we&#8217;re building a Blog-as-a-Service platform similar to Substack, called <strong>Blogstraps</strong>, and we want to implement a custom domain feature. To understand this better, let&#8217;s walk through the user journey on Substack.</p><p>When you first create a Blogstraps account, you're provided with a subdomain&#8212;let&#8217;s say <strong>coderbased.blogstraps.com</strong>. </p><p>In the settings, you can then specify a custom domain, like <strong>coderbased.com</strong>, and you'll need to update your DNS records with certain values.</p><ol><li><p>When you first create a Blogstraps account, you're provided with a subdomain&#8212;let&#8217;s say <strong>coderbased.blogstraps.com</strong>. </p></li><li><p>In the settings, you can then specify a custom domain, like <strong>coderbased.com</strong>, and you'll need to update your DNS records with certain values:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FAt-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5de050c6-7a3b-4a82-bfbb-634a04a9bc68_1170x576.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FAt-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5de050c6-7a3b-4a82-bfbb-634a04a9bc68_1170x576.png 424w, https://substackcdn.com/image/fetch/$s_!FAt-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5de050c6-7a3b-4a82-bfbb-634a04a9bc68_1170x576.png 848w, https://substackcdn.com/image/fetch/$s_!FAt-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5de050c6-7a3b-4a82-bfbb-634a04a9bc68_1170x576.png 1272w, https://substackcdn.com/image/fetch/$s_!FAt-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5de050c6-7a3b-4a82-bfbb-634a04a9bc68_1170x576.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FAt-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5de050c6-7a3b-4a82-bfbb-634a04a9bc68_1170x576.png" width="1170" height="576" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5de050c6-7a3b-4a82-bfbb-634a04a9bc68_1170x576.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:576,&quot;width&quot;:1170,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:75570,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FAt-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5de050c6-7a3b-4a82-bfbb-634a04a9bc68_1170x576.png 424w, https://substackcdn.com/image/fetch/$s_!FAt-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5de050c6-7a3b-4a82-bfbb-634a04a9bc68_1170x576.png 848w, https://substackcdn.com/image/fetch/$s_!FAt-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5de050c6-7a3b-4a82-bfbb-634a04a9bc68_1170x576.png 1272w, https://substackcdn.com/image/fetch/$s_!FAt-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5de050c6-7a3b-4a82-bfbb-634a04a9bc68_1170x576.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Setting up DNS Record</figcaption></figure></div></li><li><p>After this, you submit the request and wait for the DNS propagation</p></li><li><p>Once the DNS propagation is complete, the system processes the custom domain setup. On Substack, this process can take almost a day</p></li></ol><p>How would you design a custom domain feature? Feel free to contribute and share your ideas by filling out the form at this <a href="https://tally.so/r/wzJxLR">link</a>.</p><p>Now, let&#8217;s explore our proposed solution.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Coderbased! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Build a Custom Domain Using Multi-Tenant System Architecture</h2><p>Our solution uses the concept of a <strong>multi-tenant system architecture</strong>. Multi-tenancy allows multiple users or customer groups to access the same application or infrastructure. In MySQL or Postgres, this can be implemented by adding a <strong>tenant column</strong>. In this case, the <strong>domain</strong> column can serve this purpose.</p><p>Before we go further, we'll focus on how to use multi-tenancy to build the custom domain feature, without diving too deeply into the blog system.</p><h3>Database Design</h3><p>Let&#8217;s start with database design.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7IEh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39cfa5ee-67d6-40d4-a64f-c4c59b7c1d64_1248x576.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7IEh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39cfa5ee-67d6-40d4-a64f-c4c59b7c1d64_1248x576.png 424w, https://substackcdn.com/image/fetch/$s_!7IEh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39cfa5ee-67d6-40d4-a64f-c4c59b7c1d64_1248x576.png 848w, https://substackcdn.com/image/fetch/$s_!7IEh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39cfa5ee-67d6-40d4-a64f-c4c59b7c1d64_1248x576.png 1272w, https://substackcdn.com/image/fetch/$s_!7IEh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39cfa5ee-67d6-40d4-a64f-c4c59b7c1d64_1248x576.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7IEh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39cfa5ee-67d6-40d4-a64f-c4c59b7c1d64_1248x576.png" width="1248" height="576" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/39cfa5ee-67d6-40d4-a64f-c4c59b7c1d64_1248x576.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:576,&quot;width&quot;:1248,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:136224,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!7IEh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39cfa5ee-67d6-40d4-a64f-c4c59b7c1d64_1248x576.png 424w, https://substackcdn.com/image/fetch/$s_!7IEh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39cfa5ee-67d6-40d4-a64f-c4c59b7c1d64_1248x576.png 848w, https://substackcdn.com/image/fetch/$s_!7IEh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39cfa5ee-67d6-40d4-a64f-c4c59b7c1d64_1248x576.png 1272w, https://substackcdn.com/image/fetch/$s_!7IEh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F39cfa5ee-67d6-40d4-a64f-c4c59b7c1d64_1248x576.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Custom Domain Postgres Database Design</figcaption></figure></div><p>The most important tables and columns for implementing multi-tenancy in a custom domain feature are in the <code>project</code> table:</p><ul><li><p><code>domain</code>: Stores the Blogstraps subdomain (e.g., <strong>coderbased.blogstraps.com</strong>).</p></li><li><p><code>custom_domain</code>: Stores the actual custom domain (e.g., <strong>coderbased.com</strong>). It&#8217;s nullable, meaning if it&#8217;s null, no custom domain has been set.</p></li><li><p><code>custom_domain_status</code>: Tracks the status of the custom domain setup with values like:</p><ul><li><p><code>{status: "pending", domain: ""}</code></p></li><li><p><code>{status: "processing", domain: "coderbased.com"}</code></p></li><li><p><code>{status: "success", domain: "coderbased.com"}</code></p></li></ul></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!p1qE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281ad55e-116d-4461-987b-e26e3a6613d3_2066x260.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!p1qE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281ad55e-116d-4461-987b-e26e3a6613d3_2066x260.png 424w, https://substackcdn.com/image/fetch/$s_!p1qE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281ad55e-116d-4461-987b-e26e3a6613d3_2066x260.png 848w, https://substackcdn.com/image/fetch/$s_!p1qE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281ad55e-116d-4461-987b-e26e3a6613d3_2066x260.png 1272w, https://substackcdn.com/image/fetch/$s_!p1qE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281ad55e-116d-4461-987b-e26e3a6613d3_2066x260.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!p1qE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281ad55e-116d-4461-987b-e26e3a6613d3_2066x260.png" width="1456" height="183" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/281ad55e-116d-4461-987b-e26e3a6613d3_2066x260.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:183,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:108753,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!p1qE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281ad55e-116d-4461-987b-e26e3a6613d3_2066x260.png 424w, https://substackcdn.com/image/fetch/$s_!p1qE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281ad55e-116d-4461-987b-e26e3a6613d3_2066x260.png 848w, https://substackcdn.com/image/fetch/$s_!p1qE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281ad55e-116d-4461-987b-e26e3a6613d3_2066x260.png 1272w, https://substackcdn.com/image/fetch/$s_!p1qE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F281ad55e-116d-4461-987b-e26e3a6613d3_2066x260.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>When <code>custom_domain</code> is null, the user accesses the blog via the <code>domain</code>. If <code>custom_domain</code> is set, they can use either <code>domain</code> or <code>custom_domain</code>. We can handle database access like this:</p><pre><code>if HasSuffix(host, ".blogstraps.com")
   SELECT * FROM project WHERE domain = {host}
else 
   SELECT * FROM project where custom_domain = {host}

// p.s: Here, host refers to the domain used by the user in their browser.</code></pre><h3>High Level Design</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2zCB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F781e03d9-1675-4e86-be0a-f0b8605bf2d1_1600x398.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2zCB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F781e03d9-1675-4e86-be0a-f0b8605bf2d1_1600x398.png 424w, https://substackcdn.com/image/fetch/$s_!2zCB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F781e03d9-1675-4e86-be0a-f0b8605bf2d1_1600x398.png 848w, https://substackcdn.com/image/fetch/$s_!2zCB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F781e03d9-1675-4e86-be0a-f0b8605bf2d1_1600x398.png 1272w, https://substackcdn.com/image/fetch/$s_!2zCB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F781e03d9-1675-4e86-be0a-f0b8605bf2d1_1600x398.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2zCB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F781e03d9-1675-4e86-be0a-f0b8605bf2d1_1600x398.png" width="1456" height="362" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/781e03d9-1675-4e86-be0a-f0b8605bf2d1_1600x398.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:362,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:65220,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!2zCB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F781e03d9-1675-4e86-be0a-f0b8605bf2d1_1600x398.png 424w, https://substackcdn.com/image/fetch/$s_!2zCB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F781e03d9-1675-4e86-be0a-f0b8605bf2d1_1600x398.png 848w, https://substackcdn.com/image/fetch/$s_!2zCB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F781e03d9-1675-4e86-be0a-f0b8605bf2d1_1600x398.png 1272w, https://substackcdn.com/image/fetch/$s_!2zCB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F781e03d9-1675-4e86-be0a-f0b8605bf2d1_1600x398.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Before enabling a custom domain, if a user accesses <strong>coderbased.blogstraps.com</strong>, the request hits a reverse proxy (e.g., NGINX), which then queries Blogstraps' backend system. This is the typical request flow.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!D7QI!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a5bb9aa-0f5f-411b-99ab-d739f59ec3dc_1542x694.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!D7QI!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a5bb9aa-0f5f-411b-99ab-d739f59ec3dc_1542x694.png 424w, https://substackcdn.com/image/fetch/$s_!D7QI!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a5bb9aa-0f5f-411b-99ab-d739f59ec3dc_1542x694.png 848w, https://substackcdn.com/image/fetch/$s_!D7QI!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a5bb9aa-0f5f-411b-99ab-d739f59ec3dc_1542x694.png 1272w, https://substackcdn.com/image/fetch/$s_!D7QI!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a5bb9aa-0f5f-411b-99ab-d739f59ec3dc_1542x694.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!D7QI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a5bb9aa-0f5f-411b-99ab-d739f59ec3dc_1542x694.png" width="1456" height="655" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6a5bb9aa-0f5f-411b-99ab-d739f59ec3dc_1542x694.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:655,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:99854,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!D7QI!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a5bb9aa-0f5f-411b-99ab-d739f59ec3dc_1542x694.png 424w, https://substackcdn.com/image/fetch/$s_!D7QI!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a5bb9aa-0f5f-411b-99ab-d739f59ec3dc_1542x694.png 848w, https://substackcdn.com/image/fetch/$s_!D7QI!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a5bb9aa-0f5f-411b-99ab-d739f59ec3dc_1542x694.png 1272w, https://substackcdn.com/image/fetch/$s_!D7QI!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6a5bb9aa-0f5f-411b-99ab-d739f59ec3dc_1542x694.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When the project owner sets up a custom domain (e.g., <strong>coderbased.com</strong>), the <strong>project</strong> table is updated. A worker process periodically checks for new custom domains to process. The worker checks if the DNS for <strong>coderbased.com</strong> points to the Blogstraps backend.</p><p>The owner must configure their DNS settings (using A or CNAME records) to point to Blogstraps' servers, as described in the earlier steps. Once DNS propagation is complete, Blogstraps prepares the custom domain&#8217;s route, including redirection, and sets up SSL (using Let&#8217;s Encrypt for simplicity).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-zX6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15e5706a-160b-4fc3-95a2-2b8c9110c6bf_1584x544.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-zX6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15e5706a-160b-4fc3-95a2-2b8c9110c6bf_1584x544.png 424w, https://substackcdn.com/image/fetch/$s_!-zX6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15e5706a-160b-4fc3-95a2-2b8c9110c6bf_1584x544.png 848w, https://substackcdn.com/image/fetch/$s_!-zX6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15e5706a-160b-4fc3-95a2-2b8c9110c6bf_1584x544.png 1272w, https://substackcdn.com/image/fetch/$s_!-zX6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15e5706a-160b-4fc3-95a2-2b8c9110c6bf_1584x544.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-zX6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15e5706a-160b-4fc3-95a2-2b8c9110c6bf_1584x544.png" width="1456" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/15e5706a-160b-4fc3-95a2-2b8c9110c6bf_1584x544.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:97699,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-zX6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15e5706a-160b-4fc3-95a2-2b8c9110c6bf_1584x544.png 424w, https://substackcdn.com/image/fetch/$s_!-zX6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15e5706a-160b-4fc3-95a2-2b8c9110c6bf_1584x544.png 848w, https://substackcdn.com/image/fetch/$s_!-zX6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15e5706a-160b-4fc3-95a2-2b8c9110c6bf_1584x544.png 1272w, https://substackcdn.com/image/fetch/$s_!-zX6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F15e5706a-160b-4fc3-95a2-2b8c9110c6bf_1584x544.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Once the custom domain is set up, accessing <strong>coderbased.blogstraps.com</strong> will redirect to <strong>coderbased.com</strong>, and requests to <strong>coderbased.com</strong> will go through the Blogstraps backend.</p><p>At a high level, it may still be missing a lot of information. To understand more, let&#8217;s discuss each use case in detail.</p><h3>System Behavior Before Custom Domain Setup</h3><div class="image-gallery-embed" data-attrs="{&quot;gallery&quot;:{&quot;images&quot;:[{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e72d29f1-dee5-4d4d-9a4f-ab8c1b7a77f2_1106x770.png&quot;},{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a96b540e-19aa-4585-9719-0fdeacdd9112_1106x766.png&quot;}],&quot;caption&quot;:&quot;&quot;,&quot;alt&quot;:&quot;&quot;,&quot;staticGalleryImage&quot;:{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/38ed5fd8-5357-4818-8b41-9994cae79ebf_1456x720.png&quot;}},&quot;isEditorNode&quot;:true}"></div><p>Before the custom domain is set, accessing <strong>coderbased.com</strong> won&#8217;t route to Blogstraps System, resulting in a 500 error. However, accessing <strong>coderbased.blogstraps.com</strong> will work as follows:</p><ol><li><p>The request passes through Blogstraps' NGINX.</p></li><li><p>Blogstraps recognizes the host as <strong>coderbased.blogstraps.com</strong>.</p></li><li><p>It queries the database to fetch the articles:</p></li></ol><pre><code>// Query for accessing articles
SELECT a.* FROM article a 
INNER JOIN project p on a.project_id = p.id 
WHERE p.domain = {host}</code></pre><h3>Setting Up the Custom Domain</h3><p>The process begins when the project owner sets the <strong>custom_domain</strong> (e.g., <strong>coderbased.com</strong>). At this point, the database reflects this change.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Kiia!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81ed6534-9e94-4644-96db-68298bfe8263_2068x252.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Kiia!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81ed6534-9e94-4644-96db-68298bfe8263_2068x252.png 424w, https://substackcdn.com/image/fetch/$s_!Kiia!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81ed6534-9e94-4644-96db-68298bfe8263_2068x252.png 848w, https://substackcdn.com/image/fetch/$s_!Kiia!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81ed6534-9e94-4644-96db-68298bfe8263_2068x252.png 1272w, https://substackcdn.com/image/fetch/$s_!Kiia!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81ed6534-9e94-4644-96db-68298bfe8263_2068x252.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Kiia!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81ed6534-9e94-4644-96db-68298bfe8263_2068x252.png" width="1456" height="177" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/81ed6534-9e94-4644-96db-68298bfe8263_2068x252.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:177,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:82745,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Kiia!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81ed6534-9e94-4644-96db-68298bfe8263_2068x252.png 424w, https://substackcdn.com/image/fetch/$s_!Kiia!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81ed6534-9e94-4644-96db-68298bfe8263_2068x252.png 848w, https://substackcdn.com/image/fetch/$s_!Kiia!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81ed6534-9e94-4644-96db-68298bfe8263_2068x252.png 1272w, https://substackcdn.com/image/fetch/$s_!Kiia!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F81ed6534-9e94-4644-96db-68298bfe8263_2068x252.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Next, the owner configures the DNS, directing <strong>coderbased.com</strong> to <strong>coderbased.blogstraps.com</strong>. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!rvKf!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff95826e6-884b-4d51-81c7-89284f037f1a_984x760.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!rvKf!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff95826e6-884b-4d51-81c7-89284f037f1a_984x760.png 424w, https://substackcdn.com/image/fetch/$s_!rvKf!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff95826e6-884b-4d51-81c7-89284f037f1a_984x760.png 848w, https://substackcdn.com/image/fetch/$s_!rvKf!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff95826e6-884b-4d51-81c7-89284f037f1a_984x760.png 1272w, https://substackcdn.com/image/fetch/$s_!rvKf!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff95826e6-884b-4d51-81c7-89284f037f1a_984x760.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!rvKf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff95826e6-884b-4d51-81c7-89284f037f1a_984x760.png" width="520" height="401.6260162601626" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f95826e6-884b-4d51-81c7-89284f037f1a_984x760.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:760,&quot;width&quot;:984,&quot;resizeWidth&quot;:520,&quot;bytes&quot;:69412,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!rvKf!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff95826e6-884b-4d51-81c7-89284f037f1a_984x760.png 424w, https://substackcdn.com/image/fetch/$s_!rvKf!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff95826e6-884b-4d51-81c7-89284f037f1a_984x760.png 848w, https://substackcdn.com/image/fetch/$s_!rvKf!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff95826e6-884b-4d51-81c7-89284f037f1a_984x760.png 1272w, https://substackcdn.com/image/fetch/$s_!rvKf!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff95826e6-884b-4d51-81c7-89284f037f1a_984x760.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The background worker checks if the DNS has propagated, and once it has, NGINX configurations are updated:</p><ul><li><p>/etc/nginx/sites-available/coderbased.com</p></li><li><p>/etc/nginx/sites-enabled/coderbased.com </p></li></ul><p>At this stage, <strong>coderbased.com</strong> is connected to the Blogstraps system, but SSL is not yet set. Running <code>sudo certbot --nginx -d coderbased.com</code> will secure the domain using Let&#8217;s Encrypt.</p><p>For more details, refer to <a href="https://www.digitalocean.com/community/tutorials/how-to-secure-nginx-with-let-s-encrypt-on-ubuntu-20-04">this tutorial</a></p><p>Now, the database state reflects this change:</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!eoyi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ae362e0-5fae-442d-8e21-d2c04c3c0bb8_2068x260.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!eoyi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ae362e0-5fae-442d-8e21-d2c04c3c0bb8_2068x260.png 424w, https://substackcdn.com/image/fetch/$s_!eoyi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ae362e0-5fae-442d-8e21-d2c04c3c0bb8_2068x260.png 848w, https://substackcdn.com/image/fetch/$s_!eoyi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ae362e0-5fae-442d-8e21-d2c04c3c0bb8_2068x260.png 1272w, https://substackcdn.com/image/fetch/$s_!eoyi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ae362e0-5fae-442d-8e21-d2c04c3c0bb8_2068x260.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!eoyi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ae362e0-5fae-442d-8e21-d2c04c3c0bb8_2068x260.png" width="1456" height="183" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4ae362e0-5fae-442d-8e21-d2c04c3c0bb8_2068x260.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:183,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:85989,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!eoyi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ae362e0-5fae-442d-8e21-d2c04c3c0bb8_2068x260.png 424w, https://substackcdn.com/image/fetch/$s_!eoyi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ae362e0-5fae-442d-8e21-d2c04c3c0bb8_2068x260.png 848w, https://substackcdn.com/image/fetch/$s_!eoyi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ae362e0-5fae-442d-8e21-d2c04c3c0bb8_2068x260.png 1272w, https://substackcdn.com/image/fetch/$s_!eoyi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4ae362e0-5fae-442d-8e21-d2c04c3c0bb8_2068x260.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h3>System Behavior After Custom Domain Setup</h3><div class="image-gallery-embed" data-attrs="{&quot;gallery&quot;:{&quot;images&quot;:[{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1a3a5bc5-9cfe-4dfb-ae91-114b8e5d4b7f_1164x806.png&quot;},{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a85d3c7a-ee03-46f6-81a5-856152990a4d_1162x806.png&quot;}],&quot;caption&quot;:&quot;&quot;,&quot;alt&quot;:&quot;&quot;,&quot;staticGalleryImage&quot;:{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/98eb129f-bcf7-4ebc-81fd-55aeb106d927_1456x720.png&quot;}},&quot;isEditorNode&quot;:true}"></div><p>After the custom domain is set, accessing <strong>coderbased.blogstraps.com </strong>will trigger a redirect to <strong>coderbased.com </strong>via a 301 redirect.</p><p>First it will query:</p><pre><code>SELECT * FROM project where domain = 'coderbased.blogstraps.com'</code></pre><p>Since the query returns data indicating that the custom domain has been set, it will trigger a 301 redirect to <strong>coderbased.com</strong></p><p>At this point, the user can only access the site through <strong>coderbased.com</strong>. When the user visits <strong>coderbased.com</strong> and, for example, wants to query the articles, the system will perform a similar process but will use the custom domain instead of the <strong>.blogstraps.com</strong> suffix:</p><pre><code>SELECT a.* FROM article a 
INNER JOIN project p on a.project_id = p.id 
WHERE p.custom_domain = {host}</code></pre><div><hr></div><p>That&#8217;s all for today. If you have a system design topic you're interested in, or any other interesting system design solution for specific topic, don't hesitate to let me know&#8212;I&#8217;d be more than happy to share them here.<br><a href="https://tally.so/r/mVYLDg">Propose Topic For Next Post</a><br><a href="https://tally.so/r/wzJxLR">Propose Your Solution</a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/custom-domain-system-design?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/custom-domain-system-design?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/custom-domain-system-design/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/custom-domain-system-design/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Tech Leaders Should Stay Technical]]></title><description><![CDATA[Here&#8217;s why tech leaders should stay up-to-date with code and technology, and how to remain technical as your career grows.]]></description><link>https://www.coderbased.com/p/tech-leaders-should-stay-technical</link><guid isPermaLink="false">https://www.coderbased.com/p/tech-leaders-should-stay-technical</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Mon, 07 Oct 2024 09:45:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/6fc04cc0-d149-4be3-8db7-266bef4be0cd_1280x720.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to Coderbased, a software engineering newsletter that helps you to become hands on tech leader. Every week we write about system design, leadership, software engineering mindset or tips to become better Software Engineer.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.linkedin.com/in/herryg91">Linkedin</a>, <a href="https://twitter.com/herryg91">Twitter</a> and share this content to your friends. Enjoy.</p></blockquote><p>When I meet technical leaders (such as Heads of Engineering, Engineering Managers or even VP of Engineering) who aren&#8217;t technical&#8212;who don&#8217;t code or understand the technical aspects&#8212;I always wonder:</p><div class="pullquote"><p>&#8220;How did they rise to that position?&#8221;</p></div><p>As you advance in a company, especially on the managerial path, you take on responsibilities beyond just writing code. These can include meeting with stakeholders, developing strategies, setting KPIs, and exploring business opportunities.</p><p>However, with technology evolving rapidly, if you don&#8217;t keep up, you risk losing your technical skills.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Coderbased! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2><strong>Why should technical leaders stay technical?</strong></h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9s_6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92d16bf7-cf9d-45c1-ac79-3c46aca0c621_1580x1070.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9s_6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92d16bf7-cf9d-45c1-ac79-3c46aca0c621_1580x1070.png 424w, https://substackcdn.com/image/fetch/$s_!9s_6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92d16bf7-cf9d-45c1-ac79-3c46aca0c621_1580x1070.png 848w, https://substackcdn.com/image/fetch/$s_!9s_6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92d16bf7-cf9d-45c1-ac79-3c46aca0c621_1580x1070.png 1272w, https://substackcdn.com/image/fetch/$s_!9s_6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92d16bf7-cf9d-45c1-ac79-3c46aca0c621_1580x1070.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9s_6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92d16bf7-cf9d-45c1-ac79-3c46aca0c621_1580x1070.png" width="1456" height="986" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/92d16bf7-cf9d-45c1-ac79-3c46aca0c621_1580x1070.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:986,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:147917,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9s_6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92d16bf7-cf9d-45c1-ac79-3c46aca0c621_1580x1070.png 424w, https://substackcdn.com/image/fetch/$s_!9s_6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92d16bf7-cf9d-45c1-ac79-3c46aca0c621_1580x1070.png 848w, https://substackcdn.com/image/fetch/$s_!9s_6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92d16bf7-cf9d-45c1-ac79-3c46aca0c621_1580x1070.png 1272w, https://substackcdn.com/image/fetch/$s_!9s_6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92d16bf7-cf9d-45c1-ac79-3c46aca0c621_1580x1070.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In my view, it&#8217;s essential for tech leaders to remain technical. Here&#8217;s why:</p><h4><strong>Credibility</strong></h4><p>No software engineer wants a leader who can&#8217;t code or doesn&#8217;t understand the technical side. Staying technical allows you to empathize with your team and communicate in their language, improving collaboration and earning respect.</p><p>On the flip side, a lack of technical knowledge can lead to miscommunication and poor decision-making. You might even be <strong>misled</strong>&#8212;for example, your team could exaggerate the effort or timeline for a project.</p><h4><strong>Full Control</strong></h4><p>A tech leader&#8217;s top responsibility is hiring or promoting the right people for the right roles. When you&#8217;re technical, it&#8217;s easier to identify strong engineers, and you won&#8217;t feel anxious when someone leaves.</p><p>You&#8217;re also less reliant on others. For instance, when a critical error arises, you can contribute your insights rather than just waiting and hoping someone else will fix it.</p><p>Ultimately, this speeds up development, fosters innovation, and improves troubleshooting.</p><h4><strong>Empowering the Team</strong></h4><p>Technical leaders who stay technical are better at empowering their teams. They are seen as leaders, not just bosses. When you set realistic expectations for your team, you become a source of support rather than a burden.</p><p>I&#8217;ve seen many non-technical leaders assume that certain tasks or projects are easy when they are actually quite difficult&#8212;or even impossible. This disconnect leads to frustration and makes them a hindrance instead of a help.</p><h4>More Impact</h4><p>Leaders who lose their technical skills often shift their focus to project or people management. I&#8217;ve seen this happen frequently, especially at the middle-management level, like Engineering Managers, who end up acting as mere messengers. They can't defend their team with solid technical reasoning, which limits their impact. In the end, they just become another layer, pushing initiatives downward without adding real value.</p><p>I firmly believe that strong leadership requires a balance between top-down and bottom-up decision-making. Leaders need to understand both the technical and managerial sides to make a real difference.</p><p>P.S. This reminds me of a viral article from last year titled &#8220;The Death of Middle Management.&#8221; Is this one of the reasons why?</p><h2><strong>How to Stay Technical as a Leader</strong></h2><p>Staying technical doesn&#8217;t mean micromanaging or doing your team's work. It means ensuring that your skills stay sharp. Here are a few tips on how to do that:</p><ul><li><p><strong>Attend architecture or high-level design meetings:</strong> This keeps you informed about how your company&#8217;s systems work and ensures you&#8217;re continuously learning.</p></li><li><p><strong>Set aside research time:</strong> As you move higher in your career, dedicate more time to researching technical topics, not just attending meetings. Research allows you to discover new opportunities, whether by introducing new technology or exploring new solutions. Personal projects can also serve as valuable research.</p></li><li><p><strong>Write technical blogs or newsletters:</strong> Sharing your knowledge is a great way to reinforce your technical skills. Writing forces you to review what you know and may even inspire further research.</p></li><li><p><strong>Delegate and establish SOPs:</strong> If you&#8217;re pressed for time, consider reviewing which tasks you can delegate or automate with standard operating procedures.</p></li></ul><p>Do you have any other ideas for how technical leaders can stay technical?</p><div><hr></div><p>That&#8217;s all for today. Thank you for reading today's newsletter! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/tech-leaders-should-stay-technical?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/tech-leaders-should-stay-technical?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/tech-leaders-should-stay-technical/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/tech-leaders-should-stay-technical/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[4 Levels of Tech Debt]]></title><description><![CDATA[There are 4 levels of tech debt based on severity. What are they, and how can you reduce and prevent tech debt from spiraling out of control?]]></description><link>https://www.coderbased.com/p/4-levels-of-tech-debt</link><guid isPermaLink="false">https://www.coderbased.com/p/4-levels-of-tech-debt</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Mon, 30 Sep 2024 07:39:00 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/551ccf73-f017-4b40-b3bf-08a11b2115f2_1280x720.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to Coderbased, a software engineering newsletter that helps you to become hands on tech leader. Every week we write about system design, leadership, software engineering mindset, tips to become better Software Engineer.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.linkedin.com/in/herryg91">Linkedin</a>, <a href="https://twitter.com/herryg91">Twitter</a> and share this content to your friends. Enjoy.</p></blockquote><p>Technical Debt (Tech Debt) is called debt because it represents the technical tasks that need to be done now but are postponed for the future in favor of shortcut solutions.</p><p>I may start with something that simple such as improper database design. Then comes small issue. Fix it using workaround. Push the development and add more issue that fix through workaround. Until one day the small issues become greater issues and now it&#8217;s hard to solve it.</p><p>Technical Debt (Tech Debt) is called "debt" because it refers to the technical work that should be done now but is postponed in favor of quicker, short-term solutions.</p><p>It often starts with something simple, like a poorly designed database. Then a small issue comes up. You fix it with a workaround, push forward with development, and add more issues that also get fixed with workarounds. Eventually, those small problems grow into much larger ones, making them difficult&#8212;and expensive&#8212;to fix.</p><p>Tech Debt usually happens for a few reasons:</p><ul><li><p><strong>Improper system design</strong> &#8211; A common example is poor database design, often caused by rushed development or an inexperienced engineer.</p></li><li><p><strong>Poor code quality</strong> &#8211; This leads to bugs that are patched with quick fixes instead of proper solutions.</p></li><li><p><strong>Using outdated technology</strong> &#8211; Continuing to rely on old tools that don&#8217;t scale or perform well over time.</p></li></ul><p>Tech Debt is dangerous and tricky. Why?</p><p>It&#8217;s like a ticking time bomb. It builds up slowly, and if left unchecked, it can "explode" into serious issues. What seems like small, manageable problems at first can snowball into something much bigger. </p><p>For non-technical people, it may not seem like a big deal, and the impact of not addressing these issues isn&#8217;t always clear&#8212;until it&#8217;s too late.</p><p>That&#8217;s why, in many companies without strong engineering leadership, management often prioritizes fast development and growth, overlooking the need for proper processes. Eventually, though, the debt catches up, and it has to be paid.</p><h2>Stages of Tech Debt</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!d306!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff946d394-04f6-4b33-95b6-0fec49595de5_1304x948.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!d306!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff946d394-04f6-4b33-95b6-0fec49595de5_1304x948.png 424w, https://substackcdn.com/image/fetch/$s_!d306!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff946d394-04f6-4b33-95b6-0fec49595de5_1304x948.png 848w, https://substackcdn.com/image/fetch/$s_!d306!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff946d394-04f6-4b33-95b6-0fec49595de5_1304x948.png 1272w, https://substackcdn.com/image/fetch/$s_!d306!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff946d394-04f6-4b33-95b6-0fec49595de5_1304x948.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!d306!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff946d394-04f6-4b33-95b6-0fec49595de5_1304x948.png" width="1304" height="948" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f946d394-04f6-4b33-95b6-0fec49595de5_1304x948.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:948,&quot;width&quot;:1304,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2277085,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!d306!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff946d394-04f6-4b33-95b6-0fec49595de5_1304x948.png 424w, https://substackcdn.com/image/fetch/$s_!d306!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff946d394-04f6-4b33-95b6-0fec49595de5_1304x948.png 848w, https://substackcdn.com/image/fetch/$s_!d306!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff946d394-04f6-4b33-95b6-0fec49595de5_1304x948.png 1272w, https://substackcdn.com/image/fetch/$s_!d306!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff946d394-04f6-4b33-95b6-0fec49595de5_1304x948.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4><strong>Level 1: Minimal Impact</strong></h4><p>At Level 1, there are some reported issues, but they&#8217;re still minimal.</p><ul><li><p>Fixes are easy and don&#8217;t slow down development.</p></li><li><p>All stakeholders, including engineers, product teams, and ops, are content.</p></li><li><p>Business continues as usual with no major disruptions.</p></li></ul><h4><strong>Level 2: Emerging Problems</strong></h4><p>At Level 2, the number of reported issues begins to grow.</p><ul><li><p>Workarounds or "band-aid" fixes become common to prevent breaking existing features.</p></li><li><p>Productivity is slightly impacted, but things remain under control.</p></li><li><p>The product and engineering teams start spending more time on ad hoc issues, though it's still manageable.</p></li></ul><h4><strong>Level 3: Increasing Complexity</strong></h4><p>At Level 3, issues arise almost daily.</p><ul><li><p>Fixes become more difficult, and past technical decisions become major roadblocks.</p></li><li><p>Productivity noticeably declines.</p></li><li><p>Product and engineering teams work overtime to keep things running, patching issues as they arise.</p></li></ul><h4><strong>Level 4: Critical Breakdown</strong></h4><p>At Level 4, issues are constant.</p><ul><li><p>Frequent outages, performance issues, and cascading failures are common.</p></li><li><p>Every bug fix or update introduces new problems.</p></li><li><p>New features are either impossible or incredibly expensive to implement.</p></li><li><p>Stakeholders are experiencing burnout.</p></li><li><p>Teams outside engineering, such as ops and business, begin losing trust in the tech teams.</p></li></ul><h2>What to Do if You&#8217;re Already at Level 4?</h2><p>At Level 4, it&#8217;s not just the company that&#8217;s suffering financially due to the instability of the application&#8212;it also affects team morale and culture. To avoid reaching this point, prevention is key. Scheduling regular "tech debt payments" can help keep issues from spiraling out of control.</p><p>But what if your company is already at Level 4? Before jumping into solutions, ensure that management understands the severity of the situation.</p><p>At this stage, your system likely has deep architectural problems. It&#8217;s similar to having a house with a crumbling foundation&#8212;you can&#8217;t add new rooms or floors until you fix the base structure.</p><p>Here&#8217;s how you can approach it:</p><ul><li><p><strong>Hire an Expert</strong><br>You need a skilled software architect. If you don&#8217;t have one, hire a full-time expert or a fractional architect who can help restructure the system.</p></li><li><p><strong>Commit to Long-Term Fixes</strong><br>Reducing tech debt from Level 4 to Level 1 takes time, energy, and resources. This requires strong commitment from management and collaboration across all teams.</p></li></ul><p>There are two main approaches:</p><ol><li><p><strong>Hard Reset:</strong><br>Halt all development. The system might remain unstable, but focus all resources on laying a new foundation.</p></li><li><p><strong>Create a SWAT Team:</strong><br>Minor changes are allowed, but major changes are prohibited. The current team continues firefighting, while a new SWAT team, led by the best architect and highest leader, lays the groundwork for a new system and handles the migration.</p></li></ol><div class="poll-embed" data-attrs="{&quot;id&quot;:220985}" data-component-name="PollToDOM"></div><div><hr></div><p>That&#8217;s all for today. How&#8217;s your company&#8217;s tech debt situation? Comment below!  Thank you for reading today's newsletter! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/4-levels-of-tech-debt?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/4-levels-of-tech-debt?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/4-levels-of-tech-debt/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/4-levels-of-tech-debt/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Whatsapp Web QR Code Authentication System Design]]></title><description><![CDATA[Explaining how to build whatsapp web authentication using qr code, the architecture and the system design.]]></description><link>https://www.coderbased.com/p/whatsapp-web-qr-code-authentication</link><guid isPermaLink="false">https://www.coderbased.com/p/whatsapp-web-qr-code-authentication</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Thu, 26 Sep 2024 12:03:33 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/e8c12366-8589-484b-887e-040f1ccae2c5_1280x720.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to Coderbased, a system design newsletter that literally about designing a system that become foundation of a product and feature</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.linkedin.com/in/herryg91">Linkedin</a>, <a href="https://twitter.com/herryg91">Twitter</a> and share this content to your friends. Enjoy.</p></blockquote><p>As an engineer who has worked extensively using laptop, I love using WhatsApp over the web. One feature that stands out to me is the authentication process. It's incredibly easy, seamless, and provides an excellent user experience.</p><p>Since WhatsApp is primarily a mobile-first application, we don&#8217;t see this type of authentication method often. However, it&#8217;s still fascinating to break down how this feature works. While it&#8217;s not overly complex, it&#8217;s certainly cool to build. So, let's dive in.</p><h2><strong>Building Whatsapp Web QR Code Authentication</strong></h2><p>Imagine we have a chat application similar to WhatsApp called <strong>Coderbased Chat</strong>, and we want to implement a web authentication feature similar to WhatsApp&#8217;s. Before we proceed, let&#8217;s understand how WhatsApp&#8217;s authentication process works.</p><p>WhatsApp, being mobile-first, doesn&#8217;t use the typical methods like entering a password or receiving an OTP to log into the web version. Instead, the process is as follows:</p><ol><li><p><strong>Authenticate on the mobile app.</strong></p></li><li><p><strong>Visit</strong> <a href="https://web.whatsapp.com">web.whatsapp.com</a>, which will display a QR code.</p></li><li><p><strong>Scan the QR code</strong> using the WhatsApp app on your phone.</p></li><li><p><strong>Done!</strong> You&#8217;re now authenticated on the web version and can start chatting.</p></li></ol><p>For a visual reference, check out the illustration below..</p><div class="image-gallery-embed" data-attrs="{&quot;gallery&quot;:{&quot;images&quot;:[{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dd6e0783-bf31-4f32-8b6b-f81b17d63106_2118x1508.png&quot;},{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7033c506-4f46-43d0-9bcc-25a4331de568_2248x1242.png&quot;}],&quot;caption&quot;:&quot;Whatsapp Web QR Code Authentication &quot;,&quot;alt&quot;:&quot;Whatsapp Web QR Code Authentication &quot;,&quot;staticGalleryImage&quot;:{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/23ef72be-e218-49a3-8e79-e9c403a5a208_1456x720.png&quot;}},&quot;isEditorNode&quot;:true}"></div><p>Similar to WhatsApp, when you visit <strong>chat.coderbased.com</strong>, it will display a similar UI, including a QR code that can be scanned using the <strong>Coderbased App</strong> for authentication.</p><p>Additionally, to make the challenge more interesting, we&#8217;ve added another requirement: when the mobile app logs out (whether the session expires or the account is banned), the website should automatically log out as well.</p><blockquote><p>How would you design a system for WhatsApp Web QR Code authentication? Feel free to contribute and share your ideas by filling out the form at this <a href="https://tally.so/r/wzJxLR">link</a>.</p></blockquote><p>Now let&#8217;s go into our proposed solution</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">Thanks for reading Coderbased! Subscribe for free to receive new posts and support my work.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Proposed Solution</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8KWp!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18880afd-4fc2-47c2-ae50-fc52295e95d7_1122x846.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8KWp!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18880afd-4fc2-47c2-ae50-fc52295e95d7_1122x846.png 424w, https://substackcdn.com/image/fetch/$s_!8KWp!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18880afd-4fc2-47c2-ae50-fc52295e95d7_1122x846.png 848w, https://substackcdn.com/image/fetch/$s_!8KWp!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18880afd-4fc2-47c2-ae50-fc52295e95d7_1122x846.png 1272w, https://substackcdn.com/image/fetch/$s_!8KWp!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18880afd-4fc2-47c2-ae50-fc52295e95d7_1122x846.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8KWp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18880afd-4fc2-47c2-ae50-fc52295e95d7_1122x846.png" width="522" height="393.5935828877005" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/18880afd-4fc2-47c2-ae50-fc52295e95d7_1122x846.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:846,&quot;width&quot;:1122,&quot;resizeWidth&quot;:522,&quot;bytes&quot;:68852,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8KWp!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18880afd-4fc2-47c2-ae50-fc52295e95d7_1122x846.png 424w, https://substackcdn.com/image/fetch/$s_!8KWp!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18880afd-4fc2-47c2-ae50-fc52295e95d7_1122x846.png 848w, https://substackcdn.com/image/fetch/$s_!8KWp!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18880afd-4fc2-47c2-ae50-fc52295e95d7_1122x846.png 1272w, https://substackcdn.com/image/fetch/$s_!8KWp!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18880afd-4fc2-47c2-ae50-fc52295e95d7_1122x846.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">High Level Design</figcaption></figure></div><p>At a high level, there are several key components involved in building this feature:</p><ol><li><p><strong>Mobile App</strong> (must already be authenticated)</p></li><li><p><strong>Website</strong></p></li><li><p><strong>Chat Service</strong>: This service maintains the connection (via WebSocket) to bridge the system and frontend (both the website and mobile app). <br>It's common in chat systems to use WebSocket for two-way, real-time communication.</p></li><li><p><strong>Auth Service</strong>: Provides authentication information and tokens.</p></li></ol><p>Here are the steps and ideas to make this feature work:</p><ol><li><p>The website requests a code/token/ID, but let's call it a <strong>Guest Token</strong> from the Chat Service, which is displayed as a QR code.</p></li><li><p>The authenticated mobile app scans the QR code and retrieves the <strong>Guest Token</strong>.</p></li><li><p>The <strong>Auth Token</strong> (from the mobile app) and the <strong>Guest Token</strong> are forwarded to the Auth Service.</p></li><li><p>The Auth Service generates a new token specifically for the website, called the <strong>Web Auth Token</strong>.</p></li><li><p>The <strong>Web Auth Token</strong> is sent back to the website through the Chat Service (via WebSocket).</p></li><li><p>The website reinitializes its connection to the Chat Service, now using the <strong>Web Auth Token</strong>.</p></li></ol><p>To understand more, let&#8217;s break down the details:</p><h4>Website (Guest State): Generating the QR Code</h4><p>The website operates in two states:</p><ul><li><p><strong>Guest State</strong>: Displayed when there is no <strong>Web Auth Token</strong> stored in the browser.</p></li><li><p><strong>Authenticated State</strong>: Displayed when there is a valid <strong>Web Auth Token</strong> stored in the browser.</p></li></ul><p>By default, when a user first visits the website, it opens in <strong>Guest State</strong>, displaying the QR code for authentication.</p><p>To generate this QR code, the website connects to the Chat Service through WebSocket, identifying itself as a Guest. The Chat Service then generates the <strong>Guest Token</strong>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aXAy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55a68123-5ea5-4941-96c7-6771c2ad1442_1230x646.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aXAy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55a68123-5ea5-4941-96c7-6771c2ad1442_1230x646.png 424w, https://substackcdn.com/image/fetch/$s_!aXAy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55a68123-5ea5-4941-96c7-6771c2ad1442_1230x646.png 848w, https://substackcdn.com/image/fetch/$s_!aXAy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55a68123-5ea5-4941-96c7-6771c2ad1442_1230x646.png 1272w, https://substackcdn.com/image/fetch/$s_!aXAy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55a68123-5ea5-4941-96c7-6771c2ad1442_1230x646.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aXAy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55a68123-5ea5-4941-96c7-6771c2ad1442_1230x646.png" width="520" height="273.1056910569106" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/55a68123-5ea5-4941-96c7-6771c2ad1442_1230x646.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:646,&quot;width&quot;:1230,&quot;resizeWidth&quot;:520,&quot;bytes&quot;:69871,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aXAy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55a68123-5ea5-4941-96c7-6771c2ad1442_1230x646.png 424w, https://substackcdn.com/image/fetch/$s_!aXAy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55a68123-5ea5-4941-96c7-6771c2ad1442_1230x646.png 848w, https://substackcdn.com/image/fetch/$s_!aXAy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55a68123-5ea5-4941-96c7-6771c2ad1442_1230x646.png 1272w, https://substackcdn.com/image/fetch/$s_!aXAy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F55a68123-5ea5-4941-96c7-6771c2ad1442_1230x646.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Mobile App: Scanning the QR Code</h4><p>Now that the QR code is displayed on the website (from the Guest Token), the mobile app can scan it. </p><p>So, what happens when the QR code is scanned?</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!I8HJ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F048ed546-63fa-425c-a884-b7d09669d2b4_1352x558.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I8HJ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F048ed546-63fa-425c-a884-b7d09669d2b4_1352x558.png 424w, https://substackcdn.com/image/fetch/$s_!I8HJ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F048ed546-63fa-425c-a884-b7d09669d2b4_1352x558.png 848w, https://substackcdn.com/image/fetch/$s_!I8HJ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F048ed546-63fa-425c-a884-b7d09669d2b4_1352x558.png 1272w, https://substackcdn.com/image/fetch/$s_!I8HJ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F048ed546-63fa-425c-a884-b7d09669d2b4_1352x558.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I8HJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F048ed546-63fa-425c-a884-b7d09669d2b4_1352x558.png" width="520" height="214.6153846153846" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/048ed546-63fa-425c-a884-b7d09669d2b4_1352x558.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:558,&quot;width&quot;:1352,&quot;resizeWidth&quot;:520,&quot;bytes&quot;:64288,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!I8HJ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F048ed546-63fa-425c-a884-b7d09669d2b4_1352x558.png 424w, https://substackcdn.com/image/fetch/$s_!I8HJ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F048ed546-63fa-425c-a884-b7d09669d2b4_1352x558.png 848w, https://substackcdn.com/image/fetch/$s_!I8HJ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F048ed546-63fa-425c-a884-b7d09669d2b4_1352x558.png 1272w, https://substackcdn.com/image/fetch/$s_!I8HJ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F048ed546-63fa-425c-a884-b7d09669d2b4_1352x558.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>After scanning, the mobile app retrieves the <strong>Guest Token</strong> and sends both the <strong>Auth Token</strong> (from the mobile app) and the <strong>Guest Token</strong> to the Auth Service. These tokens are used to generate a new <strong>Web Auth Token</strong>.</p><p>The <strong>Web Auth Token</strong> is then sent to the website (browser) by notifying the Chat Service. The Chat Service, which manages all WebSocket connections, is able to send the token to the correct recipient.</p><h4>Website (Authenticated State)</h4><p>Once the <strong>Web Auth Token</strong> is received, there are two possible scenarios:</p><ol><li><p><strong>Valid Token</strong></p></li><li><p><strong>Invalid Token</strong> (e.g., expired, banned, logged out, etc.)</p></li></ol><p>Upon receiving the token, the website reinitializes by sending a message to the Chat Service via WebSocket.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_3sT!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b739969-adb3-4c35-8083-269265ff0b2f_1082x744.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_3sT!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b739969-adb3-4c35-8083-269265ff0b2f_1082x744.png 424w, https://substackcdn.com/image/fetch/$s_!_3sT!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b739969-adb3-4c35-8083-269265ff0b2f_1082x744.png 848w, https://substackcdn.com/image/fetch/$s_!_3sT!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b739969-adb3-4c35-8083-269265ff0b2f_1082x744.png 1272w, https://substackcdn.com/image/fetch/$s_!_3sT!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b739969-adb3-4c35-8083-269265ff0b2f_1082x744.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_3sT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b739969-adb3-4c35-8083-269265ff0b2f_1082x744.png" width="520" height="357.56007393715345" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7b739969-adb3-4c35-8083-269265ff0b2f_1082x744.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:744,&quot;width&quot;:1082,&quot;resizeWidth&quot;:520,&quot;bytes&quot;:75533,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!_3sT!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b739969-adb3-4c35-8083-269265ff0b2f_1082x744.png 424w, https://substackcdn.com/image/fetch/$s_!_3sT!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b739969-adb3-4c35-8083-269265ff0b2f_1082x744.png 848w, https://substackcdn.com/image/fetch/$s_!_3sT!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b739969-adb3-4c35-8083-269265ff0b2f_1082x744.png 1272w, https://substackcdn.com/image/fetch/$s_!_3sT!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7b739969-adb3-4c35-8083-269265ff0b2f_1082x744.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If the authentication is valid, the website switches from <strong>Guest State</strong> &#8594; <strong>Authenticated State</strong>, enabling full access to chat features similar to the mobile app.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!lvkC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62c03a10-f007-4101-a936-33c666aaa39b_2248x1242.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!lvkC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62c03a10-f007-4101-a936-33c666aaa39b_2248x1242.png 424w, https://substackcdn.com/image/fetch/$s_!lvkC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62c03a10-f007-4101-a936-33c666aaa39b_2248x1242.png 848w, https://substackcdn.com/image/fetch/$s_!lvkC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62c03a10-f007-4101-a936-33c666aaa39b_2248x1242.png 1272w, https://substackcdn.com/image/fetch/$s_!lvkC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62c03a10-f007-4101-a936-33c666aaa39b_2248x1242.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!lvkC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62c03a10-f007-4101-a936-33c666aaa39b_2248x1242.png" width="1456" height="804" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/62c03a10-f007-4101-a936-33c666aaa39b_2248x1242.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:804,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:567339,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!lvkC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62c03a10-f007-4101-a936-33c666aaa39b_2248x1242.png 424w, https://substackcdn.com/image/fetch/$s_!lvkC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62c03a10-f007-4101-a936-33c666aaa39b_2248x1242.png 848w, https://substackcdn.com/image/fetch/$s_!lvkC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62c03a10-f007-4101-a936-33c666aaa39b_2248x1242.png 1272w, https://substackcdn.com/image/fetch/$s_!lvkC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F62c03a10-f007-4101-a936-33c666aaa39b_2248x1242.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Mobile App: Logout Scenario</h4><p>There are two scenarios when the mobile app triggers a logout:</p><ol><li><p>The website is not connected (no user is currently connected via the website). They may connect in the future.</p></li><li><p>The website is connected, and the expectation is that the website will automatically log out in real time.</p></li></ol><p>In the first scenario, when the user later opens the website, it will reinitialize its connection to the WebSocket. During the authentication step, the Auth Service will reject the request, signaling the website to return to <strong>Guest State</strong>.</p><p>In the second scenario, the process is similar to scanning the QR code. When the mobile app triggers a logout, the Auth Service notifies the Chat Service, which sends a signal to the active connection on the website, prompting it to log out. Check the picture below</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!h4uA!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F514d5a84-1654-4b52-b664-cf64907470ed_1272x676.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!h4uA!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F514d5a84-1654-4b52-b664-cf64907470ed_1272x676.png 424w, https://substackcdn.com/image/fetch/$s_!h4uA!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F514d5a84-1654-4b52-b664-cf64907470ed_1272x676.png 848w, https://substackcdn.com/image/fetch/$s_!h4uA!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F514d5a84-1654-4b52-b664-cf64907470ed_1272x676.png 1272w, https://substackcdn.com/image/fetch/$s_!h4uA!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F514d5a84-1654-4b52-b664-cf64907470ed_1272x676.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!h4uA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F514d5a84-1654-4b52-b664-cf64907470ed_1272x676.png" width="520" height="276.3522012578616" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/514d5a84-1654-4b52-b664-cf64907470ed_1272x676.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:676,&quot;width&quot;:1272,&quot;resizeWidth&quot;:520,&quot;bytes&quot;:56441,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!h4uA!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F514d5a84-1654-4b52-b664-cf64907470ed_1272x676.png 424w, https://substackcdn.com/image/fetch/$s_!h4uA!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F514d5a84-1654-4b52-b664-cf64907470ed_1272x676.png 848w, https://substackcdn.com/image/fetch/$s_!h4uA!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F514d5a84-1654-4b52-b664-cf64907470ed_1272x676.png 1272w, https://substackcdn.com/image/fetch/$s_!h4uA!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F514d5a84-1654-4b52-b664-cf64907470ed_1272x676.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><div><hr></div><p>That&#8217;s all for today. If you have a system design topic you're interested in, or any other interesting system design solution for specific topic, don't hesitate to let me know&#8212;I&#8217;d be more than happy to share them here.<br><a href="https://tally.so/r/mVYLDg">Propose Topic For Next Post</a><br><a href="https://tally.so/r/wzJxLR">Propose Your Solution</a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/whatsapp-web-qr-code-authentication?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.coderbased.com/p/whatsapp-web-qr-code-authentication?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/whatsapp-web-qr-code-authentication/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.coderbased.com/p/whatsapp-web-qr-code-authentication/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[Online Voting System Design for Election]]></title><description><![CDATA[Designing a System to Handle Hundreds of Millions of Online Votes for an Election]]></description><link>https://www.coderbased.com/p/online-voting-system-design-for-election</link><guid isPermaLink="false">https://www.coderbased.com/p/online-voting-system-design-for-election</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Thu, 12 Sep 2024 12:00:10 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/429a8f5b-6351-42bf-aa37-74ccdeebd7eb_1280x720.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to Coderbased, a system design newsletter that literally about designing a system that become foundation of a product and feature.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.linkedin.com/in/herryg91">Linkedin</a>, <a href="https://twitter.com/herryg91">Twitter</a> and share this content to your friends. Enjoy.</p></blockquote><p>With US Election Day approaching, I&#8217;ve been thinking about designing a system for online voting. While voting systems may seem simple, handling hundreds of millions of votes within a short time frame could present significant challenges.</p><h2><strong>Building an Online Voting System</strong></h2><h3><strong>Requirements &amp; Scope</strong></h3><p>In this system design challenge, we are tasked with creating an online voting system for an election scheduled on day X in the year 2024, with 250 million voters expected to participate between 08:00 AM and 12:00 PM. The system must be designed to handle and withstand heavy traffic.</p><p><strong>Detailed Requirements &amp; Scope:</strong></p><ul><li><p>Authentication and security are out of scope. The focus is on building a system capable of handling high traffic.</p></li><li><p>An estimated 250 million voters are expected to participate.</p></li><li><p>Each user can vote for one candidate from two or more options.</p></li><li><p>Users cannot vote more than once. If a second attempt is made, the first vote will be counted.</p></li><li><p>Users should be able to view real-time results for each state. &#8220;Real-time&#8221; means a user perceives it as real-time, so a delay of one or two minutes is acceptable.</p></li></ul><p>For more clarity, see the illustration below.</p><div class="image-gallery-embed" data-attrs="{&quot;gallery&quot;:{&quot;images&quot;:[{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fa2db392-bbbc-4734-b2f0-53b1801316ca_1602x1246.png&quot;},{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67395d82-d9fa-4390-9956-a800ef0da773_2416x1518.png&quot;}],&quot;caption&quot;:&quot;Election Online Voting Illustration&quot;,&quot;alt&quot;:&quot;Election Online Voting System Requirement&quot;,&quot;staticGalleryImage&quot;:{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/53b4ab0c-7dbf-4cd3-bb40-95cdd1f8d9ee_1456x720.png&quot;}},&quot;isEditorNode&quot;:true}"></div><h3><strong>Breaking Down the Challenge</strong></h3><p>Before diving into the solution, it's important to understand why this task is challenging. Designing an online voting system for low traffic might be straightforward, but managing high traffic at this scale is much more complex.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!BGV9!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F679549ca-b5cb-498f-a903-aa2bfb93e8fc_1030x750.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!BGV9!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F679549ca-b5cb-498f-a903-aa2bfb93e8fc_1030x750.png 424w, https://substackcdn.com/image/fetch/$s_!BGV9!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F679549ca-b5cb-498f-a903-aa2bfb93e8fc_1030x750.png 848w, https://substackcdn.com/image/fetch/$s_!BGV9!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F679549ca-b5cb-498f-a903-aa2bfb93e8fc_1030x750.png 1272w, https://substackcdn.com/image/fetch/$s_!BGV9!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F679549ca-b5cb-498f-a903-aa2bfb93e8fc_1030x750.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!BGV9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F679549ca-b5cb-498f-a903-aa2bfb93e8fc_1030x750.png" width="506" height="368.4466019417476" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/679549ca-b5cb-498f-a903-aa2bfb93e8fc_1030x750.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:750,&quot;width&quot;:1030,&quot;resizeWidth&quot;:506,&quot;bytes&quot;:69912,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!BGV9!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F679549ca-b5cb-498f-a903-aa2bfb93e8fc_1030x750.png 424w, https://substackcdn.com/image/fetch/$s_!BGV9!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F679549ca-b5cb-498f-a903-aa2bfb93e8fc_1030x750.png 848w, https://substackcdn.com/image/fetch/$s_!BGV9!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F679549ca-b5cb-498f-a903-aa2bfb93e8fc_1030x750.png 1272w, https://substackcdn.com/image/fetch/$s_!BGV9!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F679549ca-b5cb-498f-a903-aa2bfb93e8fc_1030x750.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Typically, the traffic pattern shows a sharp spike in the first 5-10 minutes, after which it starts to flatten. This initial peak is the critical point where the system must be designed to handle the load.</p><p>There are two main use cases to address in an online voting system: inserting votes and showing live results.</p><h4><strong>Challenges in Displaying Live Results</strong></h4><p>Let&#8217;s assume that at least 50% of voters will cast their votes during the peak period (5 after voting opens). This translates to:</p><blockquote><p><strong>125 million voters &#247; 5 minutes = around 400,000 requests per second (RPS).</strong></p></blockquote><p>Given the unpredictability of traffic spikes, we should scale for 2x-4x the estimated load, meaning the system must handle at least 1 to 2 million RPS during peak times.</p><h4><strong>Challenges in Votes Submission</strong></h4><p>High traffic with numerous simultaneous insertions into the database can cause significant delays. A single insert query to databases like MySQL or Postgres typically takes 2-5ms. So, what happens when there are 10 million inserts?</p><blockquote><p><strong>10,000,000 &#215; 2ms (optimistic scenario) = 5.5 hours.</strong></p></blockquote><p>Given the expectation of more than 10 million requests within the first 5 minutes, inserting them all directly into the database would take 5.5 hours. For 250 million votes, it would take approximately 138 hours (5.7 days).</p><p>Basically,tThe main challenge in designing an online voting system for an election is efficiently handling high read and high write loads simultaneously.</p><blockquote><p>Question: How do you design a system that can handle  hundred millions online voting for election? Feel free to contribute and share it by filling out the form at this <a href="https://tally.so/r/wzJxLR">link</a>.</p></blockquote><p>Now let&#8217;s go to our proposed solution</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><strong>Subscribe to get posts like this</strong></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Proposed Solution</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!xg83!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1206c1b-88e2-4f95-90ea-0cb611f7cc4a_833x741.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!xg83!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1206c1b-88e2-4f95-90ea-0cb611f7cc4a_833x741.png 424w, https://substackcdn.com/image/fetch/$s_!xg83!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1206c1b-88e2-4f95-90ea-0cb611f7cc4a_833x741.png 848w, https://substackcdn.com/image/fetch/$s_!xg83!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1206c1b-88e2-4f95-90ea-0cb611f7cc4a_833x741.png 1272w, https://substackcdn.com/image/fetch/$s_!xg83!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1206c1b-88e2-4f95-90ea-0cb611f7cc4a_833x741.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!xg83!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1206c1b-88e2-4f95-90ea-0cb611f7cc4a_833x741.png" width="833" height="741" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c1206c1b-88e2-4f95-90ea-0cb611f7cc4a_833x741.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:741,&quot;width&quot;:833,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:109769,&quot;alt&quot;:&quot;High Level Design High Scalable Online Voting System Design&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="High Level Design High Scalable Online Voting System Design" title="High Level Design High Scalable Online Voting System Design" srcset="https://substackcdn.com/image/fetch/$s_!xg83!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1206c1b-88e2-4f95-90ea-0cb611f7cc4a_833x741.png 424w, https://substackcdn.com/image/fetch/$s_!xg83!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1206c1b-88e2-4f95-90ea-0cb611f7cc4a_833x741.png 848w, https://substackcdn.com/image/fetch/$s_!xg83!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1206c1b-88e2-4f95-90ea-0cb611f7cc4a_833x741.png 1272w, https://substackcdn.com/image/fetch/$s_!xg83!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1206c1b-88e2-4f95-90ea-0cb611f7cc4a_833x741.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">High Level Design High Scalable Online Voting System Design</figcaption></figure></div><p>At a high level, we propose the system design shown in the picture above. Let&#8217;s break down each component:</p><ul><li><p><strong>Database (Vote DB):</strong> We will use MySQL or Postgres because we need ACID properties. For this solution, we will use Postgres.</p></li><li><p><strong>Vote Input Service:</strong> This service handles voting submissions from voters and logs them in a vote log file. We will discuss the specifics later.</p></li><li><p><strong>Vote DB Service:</strong> This service processes the vote log file and inserts the data into the Postgres database in bulk.</p></li><li><p><strong>Vote Summarizer Service:</strong> Instead of calculating results directly from the database for every request, this service will run every minute, query the data, and cache the required information (in this case, using Redis) for displaying results.</p></li><li><p><strong>Vote Result Service:</strong> This service is a layer that presents the vote results from the Redis cache.</p></li></ul><h4><strong>Handling Votes Submission Use Case</strong></h4><p>Here&#8217;s the idea: we cannot write every request directly into the database, so we need to insert votes in bulk.</p><p><strong>Why? </strong></p><p>Inserting a large number of records one-by-one is inefficient and resource-intensive. The back-and-forth communication consumes a lot of I/O resources. Let&#8217;s compare single inserts to bulk inserts:</p><ul><li><p>A single insert requires 2-5 ms.</p></li><li><p>A bulk insert (5000 records) requires 20-25 ms.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LK8b!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1a6aeb1-c4d6-43bc-b43d-6e8aa50d7a43_1410x646.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LK8b!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1a6aeb1-c4d6-43bc-b43d-6e8aa50d7a43_1410x646.png 424w, https://substackcdn.com/image/fetch/$s_!LK8b!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1a6aeb1-c4d6-43bc-b43d-6e8aa50d7a43_1410x646.png 848w, https://substackcdn.com/image/fetch/$s_!LK8b!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1a6aeb1-c4d6-43bc-b43d-6e8aa50d7a43_1410x646.png 1272w, https://substackcdn.com/image/fetch/$s_!LK8b!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1a6aeb1-c4d6-43bc-b43d-6e8aa50d7a43_1410x646.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LK8b!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1a6aeb1-c4d6-43bc-b43d-6e8aa50d7a43_1410x646.png" width="480" height="219.91489361702128" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b1a6aeb1-c4d6-43bc-b43d-6e8aa50d7a43_1410x646.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:646,&quot;width&quot;:1410,&quot;resizeWidth&quot;:480,&quot;bytes&quot;:180025,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LK8b!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1a6aeb1-c4d6-43bc-b43d-6e8aa50d7a43_1410x646.png 424w, https://substackcdn.com/image/fetch/$s_!LK8b!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1a6aeb1-c4d6-43bc-b43d-6e8aa50d7a43_1410x646.png 848w, https://substackcdn.com/image/fetch/$s_!LK8b!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1a6aeb1-c4d6-43bc-b43d-6e8aa50d7a43_1410x646.png 1272w, https://substackcdn.com/image/fetch/$s_!LK8b!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1a6aeb1-c4d6-43bc-b43d-6e8aa50d7a43_1410x646.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Calculation:</p><blockquote><p><strong>(250 million records &#247; 5000) * 25 ms = 21 minutes</strong></p></blockquote><p>This means that between 08:00 AM and 08:21 AM, there might be a queue of data waiting to be inserted. After that, the system will process in near real-time. I believe this still offers a good real-time experience.</p><p><strong>Next, How do we handle bulk insertion?</strong></p><p>We need to queue vote data into a persistent system. The simplest solution is to use a log file, where every data entry posted through the <code>Vote Input Service</code> is appended to a persistent log file.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!XuWh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F500d5eed-c66f-4c79-9436-1a0efcfbf9b9_1752x1112.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!XuWh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F500d5eed-c66f-4c79-9436-1a0efcfbf9b9_1752x1112.png 424w, https://substackcdn.com/image/fetch/$s_!XuWh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F500d5eed-c66f-4c79-9436-1a0efcfbf9b9_1752x1112.png 848w, https://substackcdn.com/image/fetch/$s_!XuWh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F500d5eed-c66f-4c79-9436-1a0efcfbf9b9_1752x1112.png 1272w, https://substackcdn.com/image/fetch/$s_!XuWh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F500d5eed-c66f-4c79-9436-1a0efcfbf9b9_1752x1112.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!XuWh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F500d5eed-c66f-4c79-9436-1a0efcfbf9b9_1752x1112.png" width="1456" height="924" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/500d5eed-c66f-4c79-9436-1a0efcfbf9b9_1752x1112.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:924,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:201097,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!XuWh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F500d5eed-c66f-4c79-9436-1a0efcfbf9b9_1752x1112.png 424w, https://substackcdn.com/image/fetch/$s_!XuWh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F500d5eed-c66f-4c79-9436-1a0efcfbf9b9_1752x1112.png 848w, https://substackcdn.com/image/fetch/$s_!XuWh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F500d5eed-c66f-4c79-9436-1a0efcfbf9b9_1752x1112.png 1272w, https://substackcdn.com/image/fetch/$s_!XuWh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F500d5eed-c66f-4c79-9436-1a0efcfbf9b9_1752x1112.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Bulk Insert using Log File</figcaption></figure></div><p>There are 4 stages that the log file will go through until the data is bulk-inserted into the database:</p><ul><li><p><strong>Current:</strong> Every minute, the <code>Vote Input Service</code> will open a single current file, indicated by the hour and minute in its name. For example, if the current time is 08:02:33 AM, the file will be named <strong>voting-08:02.log.current</strong>. When a vote was submitted, it will be appended to this file.</p></li><li><p><strong>Waiting:</strong> Every minute, the current file is closed and renamed to a waiting file. The naming pattern will change to something like <strong>voting-08:02.log.waiting</strong>.</p></li><li><p><strong>Ready:</strong> The waiting file may contain more than 5000 records (or however many you choose for each chunk). The <code>Vote DB Service</code> will split the file into smaller ready files. For example, if <strong>voting-08:00.log.waiting</strong> contains 12,000 records, it will be split into:</p><ul><li><p><strong>voting-08:00.log.1.ready (</strong>5000 datas<strong>)</strong></p></li><li><p><strong>voting-08:00.log.2.ready (</strong>5000 datas<strong>)</strong></p></li><li><p><strong>voting-08:00.log.3.ready (</strong>2000 datas<strong>)</strong></p></li></ul></li><li><p><strong>Done:</strong> The <code>Vote DB Service</code> has another cron job that detects ready files, processes them, and bulk inserts the data into the database. After a successful insertion, the files are renamed to done, for example:</p><ul><li><p><strong>voting-08:00.log.1.ready &#8594; voting-08:00.log.1.done</strong></p></li><li><p><strong>voting-08:00.log.2.ready &#8594; voting-08:00.log.3.done</strong></p></li><li><p><strong>voting-08:00.log.2.ready &#8594; voting-08:00.log.3.done</strong></p></li></ul></li></ul><h4><strong>Handling Showing Vote Result</strong></h4><p>Now that inserting vote data into the database is clear, we need to handle how to display the vote results, where traffic can be much higher than for vote submissions.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3LDg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce1a4a1f-4ff0-4774-9b39-1c775bbcf38f_1332x562.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3LDg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce1a4a1f-4ff0-4774-9b39-1c775bbcf38f_1332x562.png 424w, https://substackcdn.com/image/fetch/$s_!3LDg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce1a4a1f-4ff0-4774-9b39-1c775bbcf38f_1332x562.png 848w, https://substackcdn.com/image/fetch/$s_!3LDg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce1a4a1f-4ff0-4774-9b39-1c775bbcf38f_1332x562.png 1272w, https://substackcdn.com/image/fetch/$s_!3LDg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce1a4a1f-4ff0-4774-9b39-1c775bbcf38f_1332x562.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3LDg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce1a4a1f-4ff0-4774-9b39-1c775bbcf38f_1332x562.png" width="1332" height="562" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ce1a4a1f-4ff0-4774-9b39-1c775bbcf38f_1332x562.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:562,&quot;width&quot;:1332,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:57673,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3LDg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce1a4a1f-4ff0-4774-9b39-1c775bbcf38f_1332x562.png 424w, https://substackcdn.com/image/fetch/$s_!3LDg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce1a4a1f-4ff0-4774-9b39-1c775bbcf38f_1332x562.png 848w, https://substackcdn.com/image/fetch/$s_!3LDg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce1a4a1f-4ff0-4774-9b39-1c775bbcf38f_1332x562.png 1272w, https://substackcdn.com/image/fetch/$s_!3LDg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fce1a4a1f-4ff0-4774-9b39-1c775bbcf38f_1332x562.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>There&#8217;s nothing particularly complex about the database design; it can be kept simple, as shown in the diagram above.</p><p>If we want to display the result based on who&#8217;s winning in each state, as illustrated in the product example, a simple query like this could work:</p><pre><code><code>SELECT s.state, v.candidate, count(vo.*) as total_vote
FROM vote v 
INNER JOIN voter vo on vo.identity_card_number = v. identity_card_number
INNER JOIN state s on s.id = vo.state
GROUP BY s.state, v.candidate</code></code></pre><p>However, running this query for every request is not scalable. Therefore, we need to implement a caching mechanism. </p><p>A typical caching mechanism using Redis follows this flow:</p><ol><li><p>Hit the <code>Vote Result Service</code>.</p></li><li><p>Check Redis for cached data.</p></li><li><p>If cached, return the data.</p></li><li><p>If not cached, query the database and cache the result.</p></li></ol><p>We cannot use this approach because it can lead to inconsistencies between different virtual machines (VMs), especially if we plan to scale horizontally. Inconsistent data is likely because vote data is increasing rapidly.</p><p>That&#8217;s why the <strong>Vote Summarizer Service</strong> is essential. This service will run a scheduled job (cron) that executes the query mentioned above and stores the result in Redis as a cache.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KzjE!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a332056-e2f6-4b18-b927-54e5881e4085_1684x536.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KzjE!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a332056-e2f6-4b18-b927-54e5881e4085_1684x536.png 424w, https://substackcdn.com/image/fetch/$s_!KzjE!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a332056-e2f6-4b18-b927-54e5881e4085_1684x536.png 848w, https://substackcdn.com/image/fetch/$s_!KzjE!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a332056-e2f6-4b18-b927-54e5881e4085_1684x536.png 1272w, https://substackcdn.com/image/fetch/$s_!KzjE!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a332056-e2f6-4b18-b927-54e5881e4085_1684x536.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KzjE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a332056-e2f6-4b18-b927-54e5881e4085_1684x536.png" width="1456" height="463" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4a332056-e2f6-4b18-b927-54e5881e4085_1684x536.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:463,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:97323,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!KzjE!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a332056-e2f6-4b18-b927-54e5881e4085_1684x536.png 424w, https://substackcdn.com/image/fetch/$s_!KzjE!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a332056-e2f6-4b18-b927-54e5881e4085_1684x536.png 848w, https://substackcdn.com/image/fetch/$s_!KzjE!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a332056-e2f6-4b18-b927-54e5881e4085_1684x536.png 1272w, https://substackcdn.com/image/fetch/$s_!KzjE!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4a332056-e2f6-4b18-b927-54e5881e4085_1684x536.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Since Redis would be a single point of failure in this setup, we need to implement Redis replication (e.g., primary and slave).</p><p>With this design, when a viewer requests the vote results, they will hit the <code>Vote Result Service</code>, which retrieves the data from the Redis cache. This approach is highly scalable&#8212;we only need to scale the service and Redis replication.</p><p><strong>Note:</strong> To make the website appear real-time, it can implement a timer to refresh and re-request the data from the <code>Vote Result Service</code>.</p><div><hr></div><p>That&#8217;s all for today. If you have a system design topic you're interested in, or any other interesting system design solution for specific topic, don't hesitate to let me know&#8212;I&#8217;d be more than happy to share them here.<br><a href="https://tally.so/r/mVYLDg">Propose Topic For Next Post</a><br><a href="https://tally.so/r/wzJxLR">Propose Your Solution</a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/online-voting-system-design-for-election?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/online-voting-system-design-for-election?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/online-voting-system-design-for-election/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/online-voting-system-design-for-election/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Multi Level Approval System Design]]></title><description><![CDATA[Designing unlimited level approval for purchase request system with set of rules including purchase amount.]]></description><link>https://www.coderbased.com/p/multi-level-approval-system-design</link><guid isPermaLink="false">https://www.coderbased.com/p/multi-level-approval-system-design</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Thu, 05 Sep 2024 14:02:10 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a74b900e-1415-4480-b34a-8b41a79cfb7b_1280x720.gif" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to Coderbased, a system design newsletter that literally about designing a system that become foundation of a product and feature.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.linkedin.com/in/herryg91">Linkedin</a>, <a href="https://twitter.com/herryg91">Twitter</a> and share this content to your friends. Enjoy.</p></blockquote><p>Hi, long time no see! We are rebranding as <strong>Coderbased</strong>, a community for coders focused on system design to build products and features. You can read more about why we decided to rebrand and focus on this specific concept <a href="https://www.coderbased.com/p/rebranding-into-coderbased">here</a>.</p><div><hr></div><h2><strong>Product &amp; System Requirements</strong></h2><p>Suppose we are software engineers for an enterprise company with an in-house ERP system. The ERP system includes a purchase module that allows employees to create purchase requests.</p><p>We have been asked to enhance the system by developing a multi-level approval process for purchase requests. For example, when an employee submits a purchase request, it needs to be approved by their supervisor. After the supervisor approves it, the request must then be approved by the manager before it can be executed.</p><p><code>Employee &#8594; Supervisor &#8594; Manager (2-Level Approval).</code></p><p><strong>Requirements &amp; Scope:</strong></p><p>While, ideally, the ERP system would require a multi-level approval process for almost all documents, let's focus solely on purchase requests (so we don't need to develop an agnostic approval system).</p><ul><li><p>The number of levels (stages) can be unlimited.</p></li><li><p>Approvers can be based on the line of superiority or selected as specific individuals.</p></li><li><p>A minimum number of approvers can be set before the workflow advances to the next level.</p></li><li><p>There can be rules based on the amount of the purchase request. For example:</p><ul><li><p>If the request is &lt;$100, it needs only one level of approval by a superior.</p></li><li><p>If the amount is &#8805;$100, it requires approval up to the managerial level.</p></li></ul></li><li><p>You can make assumptions regarding the employee structure (line of superiority). </p></li></ul><p>To understand more, check the product illustration below.</p><div class="image-gallery-embed" data-attrs="{&quot;gallery&quot;:{&quot;images&quot;:[{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/beebe4d5-8e0c-4448-86ff-14454d4a193b_2860x996.png&quot;},{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7215fae8-e2ed-4304-9111-682c8766e0f4_1042x1192.png&quot;},{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a7cd1c6a-8faf-4ff1-9a0b-f855fef145b8_2862x1010.png&quot;},{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/60be6705-7325-40d6-a403-9db4f565f987_2860x1572.png&quot;}],&quot;caption&quot;:&quot;Product/Feature Illustration&quot;,&quot;alt&quot;:&quot;Multi Level Approval Illustration&quot;,&quot;staticGalleryImage&quot;:{&quot;type&quot;:&quot;image/png&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0b3a4dc9-8ef7-41ca-9690-3acd7355ed73_1456x1456.png&quot;}},&quot;isEditorNode&quot;:true}"></div><blockquote><p>Before we present the proposed solution, we believe there are many ways to design a system to solve problems. If you have a different idea, we encourage you to contribute and share it by filling out the form at this <a href="https://tally.so/r/wzJxLR">link</a>.</p><p>We will post your solution if it is good and effectively solves the problem.</p></blockquote><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption"><strong>Subscribe to get posts like this</strong></p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Proposed Solution</h2><h3>High Level Design &amp; Architecture</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ziLZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154714b5-3e16-4133-b906-c3f9446fde0b_667x573.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ziLZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154714b5-3e16-4133-b906-c3f9446fde0b_667x573.png 424w, https://substackcdn.com/image/fetch/$s_!ziLZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154714b5-3e16-4133-b906-c3f9446fde0b_667x573.png 848w, https://substackcdn.com/image/fetch/$s_!ziLZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154714b5-3e16-4133-b906-c3f9446fde0b_667x573.png 1272w, https://substackcdn.com/image/fetch/$s_!ziLZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154714b5-3e16-4133-b906-c3f9446fde0b_667x573.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ziLZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154714b5-3e16-4133-b906-c3f9446fde0b_667x573.png" width="667" height="573" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/154714b5-3e16-4133-b906-c3f9446fde0b_667x573.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e1efba83-5102-44c9-b448-c380be2016d8_667x573.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:573,&quot;width&quot;:667,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:70529,&quot;alt&quot;:&quot;high level design multi level approval&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="high level design multi level approval" title="high level design multi level approval" srcset="https://substackcdn.com/image/fetch/$s_!ziLZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154714b5-3e16-4133-b906-c3f9446fde0b_667x573.png 424w, https://substackcdn.com/image/fetch/$s_!ziLZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154714b5-3e16-4133-b906-c3f9446fde0b_667x573.png 848w, https://substackcdn.com/image/fetch/$s_!ziLZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154714b5-3e16-4133-b906-c3f9446fde0b_667x573.png 1272w, https://substackcdn.com/image/fetch/$s_!ziLZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F154714b5-3e16-4133-b906-c3f9446fde0b_667x573.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>At a high level, there are four components and technologies that we use to solve the multi-approval system:</p><ol><li><p><strong>Purchase Service:</strong> Manages purchasing data and flow, including purchase requests.</p></li><li><p><strong>Approval Service:</strong> Manages approval configurations and the actual approval transactions for specific purchase requests.</p></li><li><p><strong>Postgres or MySQL:</strong> Both are ACID-compliant databases, which are crucial for an enterprise system. In this case, we are using Postgres.</p></li><li><p><strong>Message Broker (RabbitMQ or Kafka):</strong> Facilitates asynchronous communication between the Purchase Service and the Approval Service, ensuring they remain loosely coupled.</p></li></ol><p>There are two main user flows required to handle the multi-level approval process:</p><ul><li><p><strong>Purchase Request Creation:</strong> When an employee creates a purchase request, it will go through the existing <code>Purchase Service</code>. In our proposed solution, an additional step will inform the <code>Approval Service</code> to prepare approval transaction data based on the configured rules.</p></li><li><p><strong>Approval Flow:</strong> After the purchase request is created, its status will be set to <strong>WAIT_APPROVAL</strong>. The approval process will then proceed sequentially through stages 1, 2, and so on. If the request is rejected or all stages are approved, the Approval Service will inform the <strong>Purchase Service</strong> via the message broker, updating the status to <strong>APPROVED</strong> or <strong>REJECTED</strong></p></li></ul><p>We'll dive into the details of how this works in the use case section below.</p><h3>Database Diagram (Schema)</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8dfN!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f781287-c864-45d4-89c7-0841706e5acb_1628x1334.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8dfN!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f781287-c864-45d4-89c7-0841706e5acb_1628x1334.png 424w, https://substackcdn.com/image/fetch/$s_!8dfN!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f781287-c864-45d4-89c7-0841706e5acb_1628x1334.png 848w, https://substackcdn.com/image/fetch/$s_!8dfN!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f781287-c864-45d4-89c7-0841706e5acb_1628x1334.png 1272w, https://substackcdn.com/image/fetch/$s_!8dfN!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f781287-c864-45d4-89c7-0841706e5acb_1628x1334.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8dfN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f781287-c864-45d4-89c7-0841706e5acb_1628x1334.png" width="1456" height="1193" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6f781287-c864-45d4-89c7-0841706e5acb_1628x1334.png&quot;,&quot;srcNoWatermark&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d2435ac9-c430-4c38-9e5f-85593855887c_1628x1334.png&quot;,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1193,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:223323,&quot;alt&quot;:&quot;database erd diagram multi level approval&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="database erd diagram multi level approval" title="database erd diagram multi level approval" srcset="https://substackcdn.com/image/fetch/$s_!8dfN!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f781287-c864-45d4-89c7-0841706e5acb_1628x1334.png 424w, https://substackcdn.com/image/fetch/$s_!8dfN!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f781287-c864-45d4-89c7-0841706e5acb_1628x1334.png 848w, https://substackcdn.com/image/fetch/$s_!8dfN!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f781287-c864-45d4-89c7-0841706e5acb_1628x1334.png 1272w, https://substackcdn.com/image/fetch/$s_!8dfN!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6f781287-c864-45d4-89c7-0841706e5acb_1628x1334.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>There are four main tables for the multi-level approval system: three for configuration and one for actual transactions:</p><ul><li><p><code>pr_approval_workflow</code><strong>:</strong> This is the main table for configuring the approval workflow. You can apply rules based on the purchase request amount by setting <code>min_amount</code> and <code>max_amount</code>. If more than one rule is applied, the workflow with the higher weight will be selected.</p></li><li><p><code>pr_approval_employee</code><strong>:</strong> This table indicates who is eligible for a specific workflow. If <code>employee_id</code> is set to <code>*</code>, it means the workflow is applicable to all employees.</p></li><li><p><code>pr_approval_workflow_stage</code><strong>:</strong> This table configures the stages/levels of the workflow, including who the approvers are and how many approvals are required before moving to the next level.</p></li><li><p><code>pr_approval_transaction</code><strong>:</strong> This table records the actual approval transactions, with a direct relation to the purchase request data. </p></li></ul><h2>Let&#8217;s Breakdown the Design One by One</h2><h3>Approval Workflow Configuration</h3><p>The first thing we need to do is to define the workflow configuration, with at least one workflow needing to be designed. To make this clearer, let's use some data examples.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iSEi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16c92fe5-db5a-4f83-95de-ec4578de76dd_2340x856.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iSEi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16c92fe5-db5a-4f83-95de-ec4578de76dd_2340x856.png 424w, https://substackcdn.com/image/fetch/$s_!iSEi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16c92fe5-db5a-4f83-95de-ec4578de76dd_2340x856.png 848w, https://substackcdn.com/image/fetch/$s_!iSEi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16c92fe5-db5a-4f83-95de-ec4578de76dd_2340x856.png 1272w, https://substackcdn.com/image/fetch/$s_!iSEi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16c92fe5-db5a-4f83-95de-ec4578de76dd_2340x856.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iSEi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16c92fe5-db5a-4f83-95de-ec4578de76dd_2340x856.png" width="1456" height="533" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/16c92fe5-db5a-4f83-95de-ec4578de76dd_2340x856.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:533,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:218112,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!iSEi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16c92fe5-db5a-4f83-95de-ec4578de76dd_2340x856.png 424w, https://substackcdn.com/image/fetch/$s_!iSEi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16c92fe5-db5a-4f83-95de-ec4578de76dd_2340x856.png 848w, https://substackcdn.com/image/fetch/$s_!iSEi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16c92fe5-db5a-4f83-95de-ec4578de76dd_2340x856.png 1272w, https://substackcdn.com/image/fetch/$s_!iSEi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F16c92fe5-db5a-4f83-95de-ec4578de76dd_2340x856.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><ul><li><p><strong>Unlimited level configuration<br></strong>Let's look at the <code>pr_approval_workflow</code> and <code>pr_approval_workflow_stage</code> tables. With this setup, we can create unlimited approval levels. For example, "workflow 1" has a single approval level, while "workflow 2" has three levels of approval</p></li><li><p><strong>Purchase Request Amount-Based Rule:</strong><br>In the <code>pr_approval_workflow</code> table, workflows with IDs 1 and 2 are both eligible for all employees. However, the <code>min_amount</code> and <code>max_amount</code> fields are set so that purchase requests up to $100 will follow "workflow 1," while anything above $100 will follow "workflow 2."</p></li><li><p><strong>Specific Workflow by Weight:</strong><br>We can use the weight field for specific cases. For example, if a head-level employee makes a request over $100, they may only need approval directly from the CTO.</p></li></ul><h3>Create Purchase Request Flow</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!m8hR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F505eb2f1-9b37-4b03-ab03-b20e2c6b0f8f_1376x378.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!m8hR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F505eb2f1-9b37-4b03-ab03-b20e2c6b0f8f_1376x378.png 424w, https://substackcdn.com/image/fetch/$s_!m8hR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F505eb2f1-9b37-4b03-ab03-b20e2c6b0f8f_1376x378.png 848w, https://substackcdn.com/image/fetch/$s_!m8hR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F505eb2f1-9b37-4b03-ab03-b20e2c6b0f8f_1376x378.png 1272w, https://substackcdn.com/image/fetch/$s_!m8hR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F505eb2f1-9b37-4b03-ab03-b20e2c6b0f8f_1376x378.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!m8hR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F505eb2f1-9b37-4b03-ab03-b20e2c6b0f8f_1376x378.png" width="1376" height="378" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/505eb2f1-9b37-4b03-ab03-b20e2c6b0f8f_1376x378.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:378,&quot;width&quot;:1376,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:53644,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!m8hR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F505eb2f1-9b37-4b03-ab03-b20e2c6b0f8f_1376x378.png 424w, https://substackcdn.com/image/fetch/$s_!m8hR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F505eb2f1-9b37-4b03-ab03-b20e2c6b0f8f_1376x378.png 848w, https://substackcdn.com/image/fetch/$s_!m8hR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F505eb2f1-9b37-4b03-ab03-b20e2c6b0f8f_1376x378.png 1272w, https://substackcdn.com/image/fetch/$s_!m8hR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F505eb2f1-9b37-4b03-ab03-b20e2c6b0f8f_1376x378.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>What happens in the Approval Service when a purchase request is created?</p><p><strong>Step 1: Identify the Applicable Workflow</strong></p><p>Find the specific workflow that applies based on the eligible employee, purchase amount, and workflow weight.</p><pre><code>SELECT paw.* 
FROM pr_approval_workflow paw
INNER JOIN pr_approval_workflow_employee pawe on pawe.workflow_id = paw.id
WHERE pawe.employee_id in ('*', &lt;employee id&gt;)
AND &lt;purchase request amount&gt; BETWEEN paw.min_amount AND paw.max_amount
ORDER BY paw.weight desc 
LIMIT 1</code></pre><p><strong>Step 2: Populate </strong><code>pr_approval_transaction</code><br>Next, fill the <code>pr_approval_transaction</code> table using data from <code>pr_approval_workflow_stage</code> and the employee table.</p><p>Assume the requester is STF-001 (Phillip McDaniel), and the request amount is $100, so "workflow 2" will be applied. The expected result would look like the image below.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!oSLH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d64e562-9140-483b-b1fa-648724ed6203_1274x962.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!oSLH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d64e562-9140-483b-b1fa-648724ed6203_1274x962.png 424w, https://substackcdn.com/image/fetch/$s_!oSLH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d64e562-9140-483b-b1fa-648724ed6203_1274x962.png 848w, https://substackcdn.com/image/fetch/$s_!oSLH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d64e562-9140-483b-b1fa-648724ed6203_1274x962.png 1272w, https://substackcdn.com/image/fetch/$s_!oSLH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d64e562-9140-483b-b1fa-648724ed6203_1274x962.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!oSLH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d64e562-9140-483b-b1fa-648724ed6203_1274x962.png" width="494" height="373.0204081632653" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4d64e562-9140-483b-b1fa-648724ed6203_1274x962.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:962,&quot;width&quot;:1274,&quot;resizeWidth&quot;:494,&quot;bytes&quot;:161050,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!oSLH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d64e562-9140-483b-b1fa-648724ed6203_1274x962.png 424w, https://substackcdn.com/image/fetch/$s_!oSLH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d64e562-9140-483b-b1fa-648724ed6203_1274x962.png 848w, https://substackcdn.com/image/fetch/$s_!oSLH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d64e562-9140-483b-b1fa-648724ed6203_1274x962.png 1272w, https://substackcdn.com/image/fetch/$s_!oSLH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4d64e562-9140-483b-b1fa-648724ed6203_1274x962.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Columns<strong> </strong><code>id</code><strong>, </strong><code>purchase_request_id</code><strong>, </strong><code>workflow_id</code><strong>, </strong><code>workflow_stage_id</code><strong>, </strong><code>level</code><strong>, and </strong><code>approver_count</code> should replicate the data from the <code>pr_approval_workflow_stage</code> table.</p><p>Columns <code>approver_list</code>, <code>reject_list</code>, and <code>status</code> columns will be filled with default values since no one has approved or rejected the transaction yet. The status <code>WAIT_APPROVAL</code> indicates that the transaction is the currently active level.</p><p>The tricky part is the <code>approver</code> column, which is populated based on the <code>approver_type</code> from the <code>pr_approval_workflow_stage</code> table:</p><ul><li><p>If <code>approver_type</code> is <code>EMPLOYEE</code>, fill the column with the <code>approver_id</code> from the <code>pr_approval_workflow_stage</code> table.</p></li><li><p>If <code>approver_type</code> is <code>SUPERIOR</code>, find the approver from the employee table. The <code>approver_superior_level</code> column in the <code>pr_approval_workflow_stage</code> table indicates how many levels above the requester the approver is:</p><ul><li><p><code>1</code> = direct superior</p></li><li><p><code>2</code> = superior of the superior</p></li><li><p><code>3</code> = superior of the superior's superior</p></li><li><p>and so on.</p></li></ul></li></ul><h3>Approval Flow</h3><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Fv-h!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84327736-c139-4ab4-b903-ce694dd26a14_1272x216.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Fv-h!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84327736-c139-4ab4-b903-ce694dd26a14_1272x216.png 424w, https://substackcdn.com/image/fetch/$s_!Fv-h!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84327736-c139-4ab4-b903-ce694dd26a14_1272x216.png 848w, https://substackcdn.com/image/fetch/$s_!Fv-h!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84327736-c139-4ab4-b903-ce694dd26a14_1272x216.png 1272w, https://substackcdn.com/image/fetch/$s_!Fv-h!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84327736-c139-4ab4-b903-ce694dd26a14_1272x216.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Fv-h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84327736-c139-4ab4-b903-ce694dd26a14_1272x216.png" width="1272" height="216" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/84327736-c139-4ab4-b903-ce694dd26a14_1272x216.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:216,&quot;width&quot;:1272,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:42521,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Fv-h!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84327736-c139-4ab4-b903-ce694dd26a14_1272x216.png 424w, https://substackcdn.com/image/fetch/$s_!Fv-h!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84327736-c139-4ab4-b903-ce694dd26a14_1272x216.png 848w, https://substackcdn.com/image/fetch/$s_!Fv-h!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84327736-c139-4ab4-b903-ce694dd26a14_1272x216.png 1272w, https://substackcdn.com/image/fetch/$s_!Fv-h!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F84327736-c139-4ab4-b903-ce694dd26a14_1272x216.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><h5>Approval Level 1</h5><p>The approval flow is straightforward. Every approver who needs to approve a transaction simply queries the <code>pr_approval_transaction</code> table. In this example, the first approver is SPV-001 (Sophie Sims), so:</p><pre><code>SELECT * FROM pr_approval_transaction pat
WHERE 'SPV-001' = any(pat.approver)
AND status = 'WAIT_APPROVAL'</code></pre><p>The query above will show all approval transactions that need to be approved or rejected by SPV-001.</p><ul><li><p>If a transaction is <strong>rejected</strong>, the <strong>Approval Service</strong> will publish a message to the <strong>Message Broker</strong>, which will notify the Purchase Service to change the purchase request status from <code>WAIT_APPROVAL</code> &#8594; <code>REJECTED</code>.</p></li><li><p>If a transaction is <strong>approved</strong>, the next level (stage) of the approval process must be identified, and the status (of next level approval process) should be changed from <code>PENDING</code> to <code>WAIT_APPROVAL</code>:</p></li></ul><pre><code>UPDATE pr_approval_transaction SET status = 'APPROVED' WHERE id = $1

UPDATE pr_approval_transaction 
SET status = 'WAIT_APPROVAL'
WHERE workflow_id = &lt;current workflow_id&gt; 
AND level = &lt;current level + 1&gt;</code></pre><h5>Approval Level 2</h5><p>The flow for Level 2 is similar to Level 1, but since MGR-1 is the approver at this level, the query is:</p><pre><code>SELECT * FROM pr_approval_transaction pat
WHERE 'MGR-1' = any(pat.approver)
AND status = 'WAIT_APPROVAL'</code></pre><p>If approved, the process is updated to the next level:</p><pre><code><code>UPDATE pr_approval_transaction SET status = 'APPROVED' WHERE id = $1

UPDATE pr_approval_transaction 
SET status = 'WAIT_APPROVAL'
WHERE workflow_id = &lt;current workflow_id&gt; 
AND level = &lt;current level + 1&gt;</code></code></pre><p><strong>Approval Level 3 (Final Level)</strong></p><p>The flow for Level 3 is similar to Levels 1 and 2, but since PMG-1 is the approver at this level, the query is:</p><pre><code><code>SELECT * FROM pr_approval_transaction pat
WHERE 'PMG-1' = any(pat.approver)
AND status = 'WAIT_APPROVAL'</code></code></pre><p>If the transaction is rejected, a notification will be sent. If all levels are approved, the process continues as follows:</p><pre><code>UPDATE pr_approval_transaction SET status = 'APPROVED' WHERE id = $1

UPDATE pr_approval_transaction 
SET status = 'WAIT_APPROVAL'
WHERE workflow_id = &lt;current workflow_id&gt; 
AND level = &lt;current level + 1&gt;</code></pre><p>At this point, the last update statement will return no results since Level 3 is the final approval level. In this case, we need to trigger a message with <code>ALL_APPROVED</code> to the <strong>Message Broker</strong>, which will notify the <strong>Purchase Service</strong> to change the &#8220;purchase request status&#8221; from <code>WAIT_APPROVAL</code> &#8594; <code>APPROVED</code>.</p><div><hr></div><p>That&#8217;s all for today. If you have a system design topic you're interested in, or any other interesting system design solution for specific topic, don't hesitate to let me know&#8212;I&#8217;d be more than happy to share them here.<br><a href="https://tally.so/r/mVYLDg">Propose Topic For Next Post</a><br><a href="https://tally.so/r/wzJxLR">Propose Your Solution</a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/multi-level-approval-system-design?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/multi-level-approval-system-design?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/multi-level-approval-system-design/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/multi-level-approval-system-design/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[Using Redis Cache? Don't Forget This!]]></title><description><![CDATA[Redis is a great tool for caching, but software engineers often overlook certain aspects, leading to bugs or inefficiencies.]]></description><link>https://www.coderbased.com/p/using-redis-cache-dont-forget-this</link><guid isPermaLink="false">https://www.coderbased.com/p/using-redis-cache-dont-forget-this</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Tue, 27 Aug 2024 14:01:32 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!L12s!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to Coderbased, a newsletter designed to help you become a bit better at software engineering. We are grounded in real-world experience, not just theory and concepts. Learn one bit at a time.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.linkedin.com/in/herryg91">Linkedin</a>, <a href="https://twitter.com/herryg91">Twitter</a> and share this content to your friends. Enjoy.</p></blockquote><p>When we talk about improving application or system speed, caching is often one of the first things that comes to mind. And when it comes to caching, Redis is probably the first tool you think of.</p><p>Redis caching has been extensively discussed, so I won't rehash the basics. Instead, I want to focus on what software engineers often overlook when using Redis as a cache. These oversights can lead to potential bugs or inefficiencies.</p><p>Let&#8217;s go to the list.</p><h3>1. Forgetting to Invalidate or Clear Redis Cache</h3><p>Imagine you have an API that provides product pricing. Because your site receives high traffic, you cache the product information, including prices.</p><p>A common mistake engineers make is forgetting to invalidate or clear the cache when prices change.</p><p>For instance, if the price changes from $100 to $120, some users might still see the old $100 price if the cache isn&#8217;t properly updated.</p><p>Always plan when and how you&#8217;ll invalidate the cache to avoid these inconsistencies.</p><p>How to clear redis cache? either use <code>TTL</code> or <code>DEL</code>. In this case when the price getting update we need to trigger <code>DEL</code> statement</p><p><code>DEL product:1</code></p><h3>2. Not Caching "Not Found" Responses</h3><p>Let&#8217;s say you have an API to fetch product information by ID:</p><p><code>https://api.site.com/product/1</code></p><p>If the latest product ID in the database is 50, then IDs like 51, 52, and so on don't exist. Many engineers skip caching these "not found" responses, but this can be problematic.</p><p>When requests bypass the cache, the whole purpose of caching is undermined. In the real world, there might be cases where data existed before but no longer does, yet people still access it, perhaps through Google&#8217;s indexing. In a high-traffic environment, this can overload your server.</p><p>So, don&#8217;t forget to cache the "not found" responses as well. For example, you could cache it like this:</p><p><code>SET product:51 "{}"</code></p><h3>3. Using Redis Cache in Non-Atomic Operations</h3><p>A typical approach when using Redis for caching might look like this:</p><p><strong>GET &#8594; Process &#8594; SET</strong></p><p>If the <code>GET</code> statement finds the data in Redis, you return it. But if it doesn&#8217;t, the system must perform some processing and then cache the result with a <code>SET</code> statement.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!L12s!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!L12s!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png 424w, https://substackcdn.com/image/fetch/$s_!L12s!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png 848w, https://substackcdn.com/image/fetch/$s_!L12s!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png 1272w, https://substackcdn.com/image/fetch/$s_!L12s!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!L12s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png" width="728" height="300.5" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:601,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:113942,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!L12s!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png 424w, https://substackcdn.com/image/fetch/$s_!L12s!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png 848w, https://substackcdn.com/image/fetch/$s_!L12s!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png 1272w, https://substackcdn.com/image/fetch/$s_!L12s!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F742e17e2-4d65-4b2d-b0cf-985188108c4d_1492x616.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The problem arises in the time between the <code>GET</code> and <code>SET</code> operations. While this approach might work fine in many cases, if the process is complex, resource-intensive, or time-consuming, it can lead to a thundering herd problem.</p><p>When the process takes a long time, every request bypasses the cache, putting extra strain on the server.</p><p><strong>Suggestion:</strong> Evaluate the complexity of your logic before applying Redis caching. You can use a single-flight mechanism to ensure that when one process is being handled by the server, other requests wait until the cache is updated. Consider using <code>SETNX</code> for this.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Bosg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8e0df5-77a0-4910-bf3d-908efb19c15f_1802x728.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Bosg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8e0df5-77a0-4910-bf3d-908efb19c15f_1802x728.png 424w, https://substackcdn.com/image/fetch/$s_!Bosg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8e0df5-77a0-4910-bf3d-908efb19c15f_1802x728.png 848w, https://substackcdn.com/image/fetch/$s_!Bosg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8e0df5-77a0-4910-bf3d-908efb19c15f_1802x728.png 1272w, https://substackcdn.com/image/fetch/$s_!Bosg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8e0df5-77a0-4910-bf3d-908efb19c15f_1802x728.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Bosg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8e0df5-77a0-4910-bf3d-908efb19c15f_1802x728.png" width="1456" height="588" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ac8e0df5-77a0-4910-bf3d-908efb19c15f_1802x728.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:588,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:152534,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Bosg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8e0df5-77a0-4910-bf3d-908efb19c15f_1802x728.png 424w, https://substackcdn.com/image/fetch/$s_!Bosg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8e0df5-77a0-4910-bf3d-908efb19c15f_1802x728.png 848w, https://substackcdn.com/image/fetch/$s_!Bosg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8e0df5-77a0-4910-bf3d-908efb19c15f_1802x728.png 1272w, https://substackcdn.com/image/fetch/$s_!Bosg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fac8e0df5-77a0-4910-bf3d-908efb19c15f_1802x728.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h3>4. Forgetting to Warm Up the Cache</h3><p>When Redis is restarted or redeployed, the cache is often empty, which can lead to a spike in requests as the cache is rebuilt. If your application can handle this spike, you&#8217;re fine. But in many high-traffic environments, this can cause the system to go down.</p><p>To avoid this, set up Redis persistence and pre-fill the cache before starting the application. Warming up the cache ensures that it&#8217;s not empty when the application goes live.</p><div><hr></div><p>Did you find other things that software engineers often overlook or forget? Please comment below</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/using-redis-cache-dont-forget-this?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/using-redis-cache-dont-forget-this?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/using-redis-cache-dont-forget-this/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/using-redis-cache-dont-forget-this/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[How to Debugging]]></title><description><![CDATA[Debugging is a must-have skill for software engineers. Debugging process generally involves three stages: reproduce the bug, find root cause, fix & testing]]></description><link>https://www.coderbased.com/p/how-to-debugging</link><guid isPermaLink="false">https://www.coderbased.com/p/how-to-debugging</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Tue, 01 Aug 2023 08:00:11 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/4975a4df-f271-4ce4-85d7-a4be8f2ade02_1700x822.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to The Scalable, blog and newsletter to help you faster in becoming <em>tech leader</em>. Check our <a href="https://www.thescalable.net/p/tech-lead-roadmap">tech lead roadmaps</a>.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.threads.net/@herryg91">Threads</a> &amp; <a href="https://www.linkedin.com/in/herryg91">Linkedin</a> and share this content to your friends. Enjoy.</p></blockquote><p>Quick Links:</p><ul><li><p><a href="https://www.thescalable.net/i/135557181/intro">Intro</a></p></li><li><p><a href="https://www.thescalable.net/i/135557181/reproduce-the-bugs">Reproduce the Bugs</a></p></li><li><p><a href="https://www.thescalable.net/i/135557181/find-the-root-cause">Find the Root Cause</a></p></li><li><p><a href="https://www.thescalable.net/i/135557181/fix-and-test">Fix &amp; Test</a></p></li><li><p><a href="https://www.thescalable.net/i/135557181/tldr">TL;DR</a></p></li></ul><div><hr></div><h2>Intro</h2><p>In programming, "bugs" refer to errors or defects in a software program that cause it to behave in <strong>unexpected or unintended</strong> ways.</p><p>Writing perfect code without bugs is hard to achieve, and it&#8217;s inevitable to have bugs. That&#8217;s why <strong>debugging is a must-have skill</strong> for software engineers. Debugging is the process of identifying, analyzing, and removing bugs or defects from a software program.</p><p>While it's a must-have skill, many software engineers don't know how to debug. When they encounter a bug, they tend to resort to blind guessing, resulting in poor decision-making. Sometimes, they fail to fix the root cause, and even worse, it may lead to the generation of new bugs.</p><p>So, in today's issue, we are going to talk about the debugging process, which generally involves three stages:</p><ol><li><p>Reproduce Bugs</p></li><li><p>Find the Root Cause</p></li><li><p>Fix &amp; Test</p></li></ol><h2>Reproduce the Bugs</h2><p>The first thing we need to do when we encounter bugs is to find out how to reproduce it. Reproducing the bugs means we need to understand step-by-step <strong>how to trigger the bugs</strong> to happen. </p><p>The purpose of reproduce bugs are to identify:</p><ul><li><p>Trigger Point (on button clicked, on page load, endpoint hit, etc.)</p></li><li><p>Actual Behavior</p></li><li><p>Expected Behavior</p></li></ul><p>If we are able to reproduce the bugs, it becomes easier to solve them and ensure whether they are really resolved or just partially fixed.</p><p>There are two types of bugs in terms of occurence:</p><ol><li><p>Consistent bugs: These bugs occur every time we follow the reproduction steps, consistently producing the bugs.</p></li><li><p>Intermittent bugs: When we follow the reproduction steps, sometimes the bugs occur, and sometimes they do not.</p></li></ol><p>In my experience, if we encounter an intermittent bug, the first thing we need to do is <strong>find the intermittent variable</strong> that might affect the bug's occurrence. </p><p>These variables could be related to hardware, software versions, network connectivity, the number of servers, the volume of traffic, and other specific settings.</p><p>If we still can't understand the intermittent variable, then just jump into the next step, which is finding the root cause and going back to it when we have another clue. But remember, skipping to find the intermittent variable will make finding the root cause harder.</p><h2>Find the Root Cause</h2><blockquote><p>Note: If the bugs are super urgent, the first aid is to <strong>restart the service</strong> (or the part of the software) that is related to the bugs. We can skip finding the cause for later.</p></blockquote><p>To find out the cause of the bug, what we need to do is <strong>isolate the problem</strong>, which means we need to narrow down which part of the software or even which line of code is causing the bug.</p><p>There are 2 starting points to find the root cause:</p><ol><li><p>Read the Error Message</p><p>A good error message usually provides a clear explanation of why something is working unexpectedly. It also offers information about the specific part of the software that caused the bug. We can begin to find the root cause using this information or even try to fix the bug by searching online.</p></li><li><p>Start from the Trigger Point</p><p>In the first step, which is reproducing the bugs, one of the outcomes is that we know what triggers the bug to occur. For example, if the bug is triggered when a button is clicked, we can start by examining the function behind the button click.</p></li></ol><p>The next step is to trace back and pinpoint the bug. I often use 3 approaches to isolate and find the specific part of the software that is causing the bugs:</p><ol><li><p>Deduce from code</p><p>To start, we can thoroughly read the code and make educated guesses about which part of the code might be causing the issue. Utilize this approach when we have a strong understanding of the product and the technical aspects of the software.</p></li><li><p>Breakpoint</p><p>If deducing from the code not worked, we can use breakpoints to trace what is causing the error. The breakpoint feature allows developers to pause the execution of a program at a specific point in the code. When a breakpoint is set, the program will stop running when it reaches that line of code, allowing the developer to inspect the program's state, variable values, and the flow of execution at that particular moment. Some programming languages, especially the compiled type, usually provide the breakpoint feature.</p></li><li><p>Print statement in every line</p><p>Sometimes we can't use breakpoints, and in that case, I often use this approach. We can simply add print statements in every line of code that might be the cause of the error. Here's an example:</p><pre><code><code>func f1() {
   print("f1 called")
   f2()
   print("f2 called")
   f3()
   print("f3 called")
   f4()
   print("f4 called")
}</code></code></pre><p>If the bug happens in <code>f3()</code>, then the <code>f3 called</code> message will never be printed. So, we can isolate the problem and check the <code>f3()</code> function to identify the cause.</p></li></ol><h2>Fix &amp; Test</h2><p><strong>If we receive a good error message, then google it.</strong> We can simply <strong>"Copy &amp; Paste the error message to Google"</strong> and review the top 5 search results. In my experience, both StackOverflow and GitHub issues are very helpful in such cases. The bug you encountered might have occurred to other people and has already been resolved</p><p>However, if we are unable to solve it by Googling, it's okay as long as we have identified the part of the software that causes the bug (this is actually the most challenging part). Once we find it, we can make the necessary changes to fix the bug.</p><p>The most crucial part is <strong>testing the solution</strong>. During the reproduction phase, we understand both the actual behavior and the expected behavior. When we make changes to fix the bug (whether following information from Google or fixing it manually), we need to observe the changes in behavior and ensure it works as expected. It's important to be cautious because the changes we make might introduce new bugs. So, test it thoroughly and carefully.</p><h2>TL;DR</h2><p>Picture tells 1000 words:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UXSR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1059831-88d5-46f0-a8ef-0c6f18e5f298_2272x934.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UXSR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1059831-88d5-46f0-a8ef-0c6f18e5f298_2272x934.png 424w, https://substackcdn.com/image/fetch/$s_!UXSR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1059831-88d5-46f0-a8ef-0c6f18e5f298_2272x934.png 848w, https://substackcdn.com/image/fetch/$s_!UXSR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1059831-88d5-46f0-a8ef-0c6f18e5f298_2272x934.png 1272w, https://substackcdn.com/image/fetch/$s_!UXSR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1059831-88d5-46f0-a8ef-0c6f18e5f298_2272x934.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UXSR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1059831-88d5-46f0-a8ef-0c6f18e5f298_2272x934.png" width="1456" height="599" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c1059831-88d5-46f0-a8ef-0c6f18e5f298_2272x934.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:599,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:262810,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!UXSR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1059831-88d5-46f0-a8ef-0c6f18e5f298_2272x934.png 424w, https://substackcdn.com/image/fetch/$s_!UXSR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1059831-88d5-46f0-a8ef-0c6f18e5f298_2272x934.png 848w, https://substackcdn.com/image/fetch/$s_!UXSR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1059831-88d5-46f0-a8ef-0c6f18e5f298_2272x934.png 1272w, https://substackcdn.com/image/fetch/$s_!UXSR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc1059831-88d5-46f0-a8ef-0c6f18e5f298_2272x934.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p></p><div><hr></div><p>That&#8217;s it for today, thank you for reading! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thescalable.net/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Scalable&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.thescalable.net/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Scalable</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/how-to-debugging/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/how-to-debugging/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[One-on-One Meeting as Software Engineer (Mentee): Proactive!]]></title><description><![CDATA[One-on-one meeting is not just for the leader, You can also derive many benefits from it such as for career growth and solve problems. The important point is you need to be proactive.]]></description><link>https://www.coderbased.com/p/one-on-one-meeting-as-software-engineer</link><guid isPermaLink="false">https://www.coderbased.com/p/one-on-one-meeting-as-software-engineer</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Tue, 25 Jul 2023 08:00:18 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d5c2d86a-06cc-49fe-9af4-c2cbb12c6918_1374x822.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to The Scalable, blog and newsletter to help you faster in becoming <em>tech leader</em>. Check our <a href="https://www.thescalable.net/p/tech-lead-roadmap">tech lead roadmaps</a>.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.threads.net/@herryg91">Threads</a> &amp; <a href="https://www.linkedin.com/in/herryg91">Linkedin</a> and share this content to your friends. Enjoy.</p></blockquote><p>Quick Links:</p><ul><li><p><a href="https://www.thescalable.net/i/135419326/intro">Intro</a></p></li><li><p><a href="https://www.thescalable.net/i/135419326/utilize-one-on-one-meeting">Utilize One-on-One Meeting</a></p></li><li><p><a href="https://www.thescalable.net/i/135419326/you-need-to-become-proactive">Be Proactive</a></p></li><li><p><a href="https://www.thescalable.net/i/135419326/tldr">TL;DR</a></p></li></ul><div><hr></div><h2>Intro</h2><p>Last week, I wrote about one-on-one meetings for managers and tech leaders, focusing on how to effectively lead these meetings. You can check the link below to gain insights from tech leaders who have utilized this meeting format.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;68a41aa7-2d72-4ee5-9de5-8753282111ba&quot;,&quot;caption&quot;:&quot;Welcome to The Scalable, blog and newsletter to help you faster in becoming tech leader. Check our tech lead roadmaps. Before we start, kindly to subscribe, follow me on Threads &amp; Linkedin and share this content to your friends. Enjoy. Quick Links: Intro&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;One-on-One Guidelines for Manager / Tech Leader&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:140347336,&quot;name&quot;:&quot;Herry Gunawan&quot;,&quot;bio&quot;:&quot;Writing Hands-on DB | CTO &amp; Co-Founder Gajiku\n\nI have a lot of experience in building scalable systems and products. One example is when I successfully managed a 500x increase in traffic during the biggest event in my country.\n&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/85021d27-1a23-4cba-9a97-4318cfb7cc18_512x512.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-07-18T10:00:36.068Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f2988e73-11ad-465d-8b3e-5bb9e4d9e5e0_1552x1008.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.thescalable.net/p/one-on-one-guidelines-for-manager&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:135066306,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:0,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;The Scalable&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb456-151d-43a1-9ffc-2f694121655c_500x500.png&quot;,&quot;belowTheFold&quot;:false,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>Today's discussion is a continuation of the previous topics, but this time, we will focus on the other party involved: the Software Engineer (or mentee). The topic for today is how to maximize the one-on-one meetings with your manager to ensure that you gain numerous benefits from them.</p><p>Let's get started!</p><h2>Utilize One-on-One Meeting</h2><p>One misconception about one-on-one meetings is that many people, especially junior or new software engineers, think of it as a place for the leaders to simply give directions (one-way communication). </p><p>However, it is more than that. There are many benefits for software engineers if they can utilize these meetings effectively. What are they?</p><h5>Utilize It for Career Growth</h5><p>Yes, one-on-one meetings are a great opportunity to define your career goals and foster career growth. If your manager or leaders have not brought up this topic, you should ask them to discuss it. To utilize it, you need to ensure at least these three things below:</p><ol><li><p>You have to talk about the clear requirements for you to reach the next career level.</p></li><li><p>Ensure that the list is measurable.</p></li><li><p>Review the progress toward these goals during each one-on-one meeting.</p></li></ol><p>By following these three steps, you can proactively track your performance and development. Additionally, this approach enables your leaders to make objective judgments when considering your eligibility for promotion.</p><h5>Utilize it for Solving Problems</h5><p>Common problems that often happen in the workplace are <strong>misalignment, misexpectation</strong> and <strong>miscommunication</strong>. In short it is a gap.</p><p>With one-on-one meetings, you can solve these problems by:</p><ol><li><p>Setting clear expectations.</p></li><li><p>Engaging in open communication to address the issues.</p></li><li><p>Creating an action plan to resolve the problems.</p></li></ol><p>Remember that you are allowed to have expectations from your leaders, and it is crucial to communicate them. Your leader, at least your direct reportee, should be aware of your expectations. This approach can help bridge gaps and solve many issues.</p><h5>Utilize it to Build Trust</h5><p>A one-on-one meeting is a valuable opportunity to get to know each other better and build trust. It provides a platform for analyzing the behavior of your leaders, understanding their preferences, and identifying what they consider important.</p><p>As your leader is the decision maker, knowing and being able to influence them can significantly improve your work life, making it much easier to navigate.</p><h2>You Need to Become Proactive</h2><p>I often encounter average software engineers who grumble a lot about things they don't like, such as decisions, culture, or even their teammates. However, it's essential to understand that your career and happiness in the company are your responsibility, not your leader's alone. Therefore, taking ownership of the one-on-one meeting is also your responsibility.</p><p>If you have a good leader who genuinely cares about their subordinates and conducts effective one-on-one meetings, consider yourself lucky. However, in reality, you may encounter leaders with different approaches to connecting with their co-workers.</p><p>This validates the need for you to become proactive. Don't wait for your leader to spoon-feed you. In the context of one-on-one meetings, it means:</p><ul><li><p>It's okay for you to initiate the one-on-one meeting.</p></li><li><p>You should proactively bring up relevant topics in the meeting.</p></li><li><p>You should be the one who writes up and cares about the results of the meeting, including the action plan.</p></li></ul><h2>TL;DR</h2><p>In summary, a one-on-one meeting is not just for your leader; you can also derive many benefits from it if you utilize it effectively. You can contribute to your career growth, solve problems, and build trust between co-workers through these meetings. Additionally, you need to be proactive instead of waiting for your leader to spoon-feed you. It means you should feel comfortable initiating the meeting, expressing your expectations to your leader, directing the topics of discussion, and more. Take charge of these meetings to make the most of them for your personal and professional development.</p><div><hr></div><p>That&#8217;s it for today, thank you for reading! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/one-on-one-meeting-as-software-engineer?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/one-on-one-meeting-as-software-engineer?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/one-on-one-meeting-as-software-engineer/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/one-on-one-meeting-as-software-engineer/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[One-on-One Guidelines for Manager / Tech Leader]]></title><description><![CDATA[One-on-one meetings are an effective routine that yields positive results. Learn valuable guidelines on what to discuss in one-on-one meetings as a manager or tech leader, and discover what constitute]]></description><link>https://www.coderbased.com/p/one-on-one-guidelines-for-manager</link><guid isPermaLink="false">https://www.coderbased.com/p/one-on-one-guidelines-for-manager</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Tue, 18 Jul 2023 10:00:36 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f2988e73-11ad-465d-8b3e-5bb9e4d9e5e0_1552x1008.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to The Scalable, blog and newsletter to help you faster in becoming <em>tech leader</em>. Check our <a href="https://www.thescalable.net/p/tech-lead-roadmap">tech lead roadmaps</a>.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.threads.net/@herryg91">Threads</a> &amp; <a href="https://www.linkedin.com/in/herryg91">Linkedin</a> and share this content to your friends. Enjoy.</p></blockquote><p>Quick Links:</p><ul><li><p><a href="https://www.thescalable.net/i/135066306/intro">Intro</a></p></li><li><p><a href="https://www.thescalable.net/i/135066306/why-are-one-on-one-important-for-managers-and-tech-leaders">Why Important?</a></p></li><li><p><a href="https://www.thescalable.net/i/135066306/what-should-be-discussed-during-a-one-on-one-meeting-as-manager-tech-leader">One-on-One Questions and To Do</a></p></li><li><p><a href="https://www.thescalable.net/i/135066306/how-does-a-good-one-on-one-meeting-look-like">How Does Good 1:1 Look Like?</a></p></li><li><p><a href="https://www.thescalable.net/i/135066306/tldr">TL;DR</a></p></li></ul><div><hr></div><h2>Intro</h2><p>I am often asked by many tech leaders about their routine in their company, and all of them always mention doing one-on-one meetings.</p><p>Currently, conducting one-on-one meetings is a proven practice that is a must for tech leaders. However, I have also heard that many people, especially new managers or leaders, find it hard to engage in one-on-one meetings. Most of them don't know what to do during these meetings.</p><p>Therefore, in today's discussion, we will delve into the topic of one-on-one meetings from the perspective of a manager or mentor. We will talk about the importance of conducting one-on-one meetings, what to ask, and what a good one-on-one meeting should look like.</p><p>Before we explore what to do in a one-on-one meeting, it is essential to understand what a one-on-one meeting is and why it's important.</p><h2>Why are One-on-One Important for Managers &amp; Tech Leaders?</h2><p>For those of you who have never heard of a one-on-one meeting,  basically it is a routine where a manager/leader/mentor meets with an employee to discuss various work-related matters. Typically, these discussions revolve around topics such as career development, goals, projects, and issues.</p><p>One-on-one meetings have been proven to have positive impacts, such as improving employee engagement. Employee engagement is closely linked to employee performance.</p><div class="pullquote"><p>Managers who regularly meet with their employees almost tripled that level of engagement. <a href="https://news.gallup.com/businessjournal/174197/managers-focus-performance-engagement.aspx">Source</a></p></div><p>Basically, I have categorized the purposes (for managers/leaders) of conducting one-on-one meetings into two:</p><ol><li><p>Solving problems<br>Have you ever heard the phrase, "Most of your problems can be solved by talking"? Incorporating one-on-one meetings as a regular practice definitely helps reduce misunderstandings and assumptions that often lead to employee-company problems</p></li><li><p>Decision-making<br>By regularly having these meetings, mutual understanding can be fostered, which ultimately proves useful in making decisions. <br>For example, I have a friend who is a tech leader and didn't face difficulties when deciding back to WFO because he knew who supported and opposed the idea. He also have a strategy how to handle the opposing viewpoints</p></li></ol><p>Engaging in one-on-one meetings offers numerous advantages compared to disadvantages. So, why not give it a try?</p><h2>What Should be Discussed during a One-on-One Meeting as Manager / Tech Leader?</h2><p>Now that we understand the importance of conducting one-on-one meetings, it's important to address the issue that many people, especially new managers/leaders, don't know what to do during these meetings. This can result in unproductive meetings with no clear purpose. </p><p>In this section, we will delve into what should be discussed during a one-on-one meeting.</p><h5>Organization &amp; Company Awareness</h5><p>Organization here can refer to a team, division, or even a company. Organization awareness is crucial as it pertains to an individual's understanding and knowledge of an organization's purpose, goals, values, structure, culture, and operations.</p><p>Often, when decisions are made within an organization, there is a risk of being misunderstood by its members. By initiating discussions about organization and company awareness, it helps enhance the employee's <strong>sense of belonging</strong>.</p><p>Here are some actions and questions you can use during a one-on-one meeting:</p><ul><li><p>Company &amp; Team Updates:</p><ul><li><p>"I would like to provide you with an update on the company."</p></li><li><p>"Recently, our company made a decision to transition back to working from the office (WFO). You may have opposing views, but let me explain the thought process behind this decision."</p></li></ul></li><li><p>Management, Team, and Company Culture:</p><ul><li><p>"On a scale of 1 to 10, what is your approval rating for our management and CEO?"</p></li><li><p>"Is there anyone in the team you would like to express gratitude to?"</p></li><li><p>"How would you describe your relationships with your co-workers? Are there any issues or areas for improvement?"</p></li><li><p>"How do you feel about our company culture?"</p></li><li><p>"What aspects of our team culture did you like the most and the least?"</p></li></ul></li><li><p>Organization Purpose, Direction, and Future Projects:</p><ul><li><p>"Do you have a clear understanding of our company's purpose?"</p></li><li><p>"Do you have any ideas regarding features, products, or projects that we should prioritize?"</p></li><li><p>"What opportunities do you think we might have missed?"</p></li><li><p>"This semester, our focus will be on achieving specific Key Performance Indicators (KPIs). Here's the big picture behind why we are pursuing these objectives and why they are important."</p></li><li><p>"What do you like about our products?"</p></li></ul></li></ul><h5>Goals &amp; Expectation</h5><p>Another important topic to discuss is goals and expectations.</p><p>Not always, but most employees might want to talk about their careers and how they can achieve their career goals. Therefore, career goals are also part of this kind of discussion.</p><p>Here are some actions and questions you can use:</p><ul><li><p>Goal Setting:</p><ul><li><p>"Where do you see yourself in the company in the next 5 years?"</p></li><li><p>"What are your plans for next week?"</p></li><li><p>"Do you have any career goals? How long do you intend to achieve them?"</p></li><li><p>"Does working in this company help you achieve your goals?"</p></li><li><p>&#8220;What skills you want to improve?&#8221;</p></li></ul></li><li><p>Aligning Expectations and Requesting Feedback:</p><ul><li><p>"How clear do you feel about what is expected of you?"</p></li><li><p>"Let's establish a mutual agreement on what we should and shouldn't do."</p></li><li><p>"What are your red flags? For me, a red flag is failing to communicate effectively. What about you?"</p></li><li><p>"Let's discuss how we can resolve conflicts. Do you prefer a direct or indirect approach?"</p></li><li><p>"What do you think I need to improve?"</p></li><li><p>"If you were in my position, what are 1-2 things you would change?"</p></li></ul></li><li><p>Career and Growth Plan:</p><ul><li><p>"What can I do to help you grow?"</p></li><li><p>"In the last 3 months, I have seen improvement in your skills. Keep up the consistency."</p></li><li><p>"You were mentioned on Slack, but you haven't replied. This is unacceptable, how can we fix this?"</p></li><li><p>"If you want to get promoted in the next performance review, here are the things you need to demonstrate!"</p></li><li><p>"Who in the company would you be excited to learn more from?"</p></li><li><p>"What parts of the business would you like to be more involved in?"</p></li></ul></li></ul><ul><li><p>Milestone &amp; Celebrate Success</p><ul><li><p>"Congratulations! The last project you were involved in achieved the predicted KPIs."</p></li><li><p>"Thank you for delivering the project on time."</p></li></ul></li></ul><h5>Setup Routine</h5><p>What contributes to the success of employee goals is having a routine or system in place. It becomes easier when you have specific actions, such as "reviewing at least 10 pull requests per week" or "speaking up in meetings at least twice a week," and so on.</p><p>Here are some actions and questions you can use:</p><ul><li><p>Identifying Opportunities:</p><ul><li><p>"Are there any recurring ad hoc tasks that we should address?"</p></li><li><p>"I noticed that the operations team frequently needs help finding bugs. Perhaps you can dedicate one hour in the morning to assist them."</p></li><li><p>"We agreed that misunderstandings of requirements have been causing delays. How about making it a routine to re-explain the requirements during brainstorming sessions?"</p></li><li><p>"Do you have any ideas on what problems can be solved by creating a routine or procedure?"</p></li></ul></li><li><p>Reviewing the Routine:</p><ul><li><p>"Are we comfortable having this one-on-one meeting every week, or would you prefer it to be biweekly?"</p></li><li><p>"Do you feel that you attend too many meetings?"</p></li></ul></li></ul><h5>Health Check</h5><p>One-on-one meetings can be used to "health check" employee happiness and engagement, as happy employees tend to yield better results.</p><ul><li><p>Employee Happiness</p><ul><li><p>"Are you generally happy working in this company?"</p></li><li><p>"Which part of your work is the most enjoyable?"</p></li><li><p>"What aspects of working here are not enjoyable for you?"</p></li><li><p>"What are the biggest time-wasters for you each week?"</p></li><li><p>"Which projects or tasks bring you happiness?"</p></li></ul></li><li><p>Personal</p><ul><li><p>"How is life outside of work?"</p></li><li><p>"What did you do last weekend?"</p></li><li><p>"How are your family/children doing?"</p></li><li><p>"I noticed a decline in your performance recently. Is there any personal or family issue that may be affecting you?"</p></li><li><p>"What&#8217;s your hobby? do you play game?"</p></li></ul></li></ul><h2>How Does a Good One-on-One Meeting Look Like?</h2><p>There are several parameters that identify a good one-on-one meeting:</p><p><strong>Clear agendas:</strong> Before the one-on-one meeting, both parties should understand the topics to be discussed and come prepared. In the previous section, we discussed what to do in a one-on-one meeting, and you can use one or some of those topics as the agenda.</p><p><strong>Two-way discussion:</strong> A good one-on-one meeting should facilitate a two-way discussion where both parties get to know each other better and work together to solve problems, rather than it being a one-sided lecture.</p><p><strong>Action plan:</strong> The best outcome of a one-on-one meeting is the establishment of an agreed-upon action plan. This plan can involve both the manager/leader and the employee who participated in the one-on-one.</p><p><strong>Positive results:</strong> A good one-on-one meeting often leads to a more motivated employee, clarifies any areas of uncertainty, and helps the employee improve in some way.</p><h2>TL;DR</h2><p>A one-on-one meeting is a crucial routine that should be held by managers and tech leaders. It serves as a means to solve problems, build relationships, and enhance employee engagement. If you are unsure about what to do in a one-on-one meeting, focus on the following topics: organization and company awareness, goals and expectations, setting up routines, and employee happiness.</p><p>A good one-on-one meeting typically involves clear agendas, facilitating a two-way discussion between both parties, and yielding positive outcomes such as increased employee motivation and the establishment of clear action plans.</p><div><hr></div><p>That&#8217;s it for today, thank you for reading! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/one-on-one-guidelines-for-manager?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/one-on-one-guidelines-for-manager?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/one-on-one-guidelines-for-manager/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/one-on-one-guidelines-for-manager/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[Software Engineer: Work Hard vs Work Smart?]]></title><description><![CDATA[Are you a work hard or a work smart software engineer? Actually you can have both work hard and work smart depend on the situation.]]></description><link>https://www.coderbased.com/p/software-engineer-work-hard-vs-work</link><guid isPermaLink="false">https://www.coderbased.com/p/software-engineer-work-hard-vs-work</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Tue, 11 Jul 2023 08:01:08 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/49d0fff6-a5f0-4250-bfec-ff2d5cd66e3a_1844x1086.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to The Scalable, blog and newsletter to help you faster in becoming <em>tech leader</em>. Check our <a href="https://www.thescalable.net/p/tech-lead-roadmap">tech lead roadmaps</a>.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://www.threads.net/@herryg91">Thread</a> &amp; <a href="https://www.linkedin.com/in/herryg91">Linkedin</a> and share this content to your friends. Enjoy.</p></blockquote><p>Quick Links:</p><ul><li><p><a href="https://www.thescalable.net/i/134221171/intro">Intro</a></p></li><li><p><a href="https://www.thescalable.net/i/134221171/fake-smart-workers">Fake Smart Workers</a></p></li><li><p><a href="https://www.thescalable.net/i/134221171/work-hard-vs-work-smart-misconception">Misconception of Work Hard vs Work Smart</a></p><ul><li><p><a href="https://www.thescalable.net/i/134221171/becoming-a-smart-worker-isnt-easy">Becoming a Smart Worker is not Easy</a></p></li><li><p><a href="https://www.thescalable.net/i/134221171/hard-work-first-then-learn-to-work-smartly">Hard Work First before Work Smart</a></p></li></ul></li><li><p><a href="https://www.thescalable.net/i/134221171/herry-are-you-work-hard-or-work-smart">Answering &#8220;Are You Work Hard or Work Smart?&#8221;</a></p></li><li><p><a href="https://www.thescalable.net/i/134221171/tldr">TL;DR</a></p></li></ul><h2>Intro</h2><p><code>Work Hard</code> and <code>Work Smart</code> are two phrases often used in the context of productivity and success.</p><p><strong>Work hard</strong> emphasizes the importance of putting in effort, dedicating time, and having a strong work ethic to achieve goals.</p><p><strong>Work smart</strong> emphasizes the efficiency of your effort to maximize the result.</p><p>Over 80% of the software engineers I've met claim to be a smart worker rather than hard worker, but most of them are just average software engineers. On the other hand, those who call themselves hard worker are mostly great engineers.</p><p>How can this happen?</p><p>In today's discussion, we will be talking about work hard, work smart, and the misconceptions about them. Initially, I am not a fan of working smart. Why? Let's find out.</p><h2>Fake Smart Workers</h2><p>Every time I conduct an interview with a software engineer, one question that I often ask is: </p><blockquote><p>Do you work hard or work smart?</p></blockquote><p>My intention in asking this question is to understand their work behavior, especially to determine if they are lazy (continuous learner) or not.</p><p>I don't directly ask, <em>"Are you a hard worker?"</em> because the answer is easy to fabricate.</p><p>On the other hand, adding <strong>work smart</strong> as a comparison makes the results more interesting. If the engineer answers with "I am a hard worker," then they are likely telling the truth. Because if they are not, answering with "work smart" is more appealing and cool.</p><p>More than 80% of them answer with "work smart," and most of them (not all) are fake.</p><p>How can I know?</p><p>When I add a follow-up question, "What's the proof?" they cannot answer it.</p><p>Note: Now I need to remove this question &#128514;</p><h2>Work Hard vs Work Smart (Misconception)</h2><blockquote><p>Are there any people who claim to be smart workers without faking it? </p></blockquote><p>The answer is yes, but not many. However, that's not the real problem. The real problem lies in why we need to choose between those two.</p><p>I would say that this misconception arises in society because many people, including coaches, influencers, and motivators, glorify working smart over working hard.</p><p>I believe that working smart can be achieved after working hard enough.</p><h4>Becoming a smart worker isn&#8217;t easy</h4><p>Let's discuss this with an example (which actually happened in real life).</p><p>Imagine you are working in a company that uses Kubernetes as its infrastructure. You are managing hundreds of microservices, and there's a problem with the deployment process. It becomes a hurdle when you have to write the YAML files one by one.</p><p>One of the smart moves is to "create a tech tool" to automate the deployment. However, to achieve that, you need:</p><ul><li><p>Understanding of how Kubernetes works</p></li><li><p>Strong technical proficiency to develop the tool</p></li><li><p>Designing a suitable tool</p></li><li><p>Dedicated time to develop it</p></li><li><p>And more</p></li></ul><p>If you look at the list above, it becomes clear that you need to work hard to learn and gain experience in many areas. If you haven't worked hard enough, you may not even be aware that you can create a tool to solve the problem.</p><h4>Hard Work first then learn to work smartly</h4><p>Working smart has prerequisites, unlike working hard, which everyone is capable of doing. Therefore, in order to work smartly, you need to acquire a lot of knowledge and experience. All of this can be achieved by investing a significant amount of time.</p><p>Once you have gained a substantial amount of knowledge and experience, it's time for you to learn how to work smart. This is crucial because there are many people who stop at working hard. After acquiring a vast amount of knowledge, they fail to learn how to work smartly, leading to burnout.</p><h2>Herry, Are you Work Hard or Work Smart?</h2><p>I will answer it by saying both. It depends on the situation, but essentially, I am a hard worker.</p><p>Here are some actions where I adopt a work hard approach:</p><ol><li><p>When learning and keeping up with new technology.</p></li><li><p>Spending time writing <em><strong>thescalable</strong></em> every day.</p></li></ol><p>Here are some actions where I adopt a work smart approach:</p><ol><li><p>Solving recurring problems by building tech tools.</p></li><li><p>When it comes to prioritization and planning, I tend to find ways to limit the scope while still achieving the goals.</p></li></ol><h2>TL;DR</h2><p>You can't work smart if you haven't worked hard enough, especially in the field of software engineering. You need to invest effort in learning, gaining fundamentals, and more before you can utilize them to become work smart.</p><p>It's not about choosing between working hard or working smart. They can even be used together. There are instances where you work smart on one task and work hard on another.</p><div><hr></div><p>That&#8217;s it for today, thank you for reading! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/software-engineer-work-hard-vs-work?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/software-engineer-work-hard-vs-work?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/software-engineer-work-hard-vs-work/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/software-engineer-work-hard-vs-work/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[How Does a Great Junior Software Engineer Look Like?]]></title><description><![CDATA[Characteristics of good junior software engineering: technical skill, soft skill, behavior and more]]></description><link>https://www.coderbased.com/p/how-does-a-great-junior-software</link><guid isPermaLink="false">https://www.coderbased.com/p/how-does-a-great-junior-software</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Tue, 04 Jul 2023 09:01:18 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/624b3bac-0f45-4d53-85f6-eaaaa25a6380_1298x740.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to The Scalable, blog and newsletter to help you faster in becoming <em>tech leader</em>. Check our <a href="https://www.thescalable.net/p/tech-lead-roadmap">tech lead roadmaps</a>.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://twitter.com/herryg91">Twitter</a> &amp; <a href="https://www.linkedin.com/in/herryg91">Linkedin</a> and share this content to your friends. Enjoy.</p></blockquote><p>Quick Links:</p><ul><li><p><a href="https://www.thescalable.net/i/132827621/intro">Intro</a></p></li><li><p><a href="https://www.thescalable.net/i/132827621/technical-skill">Technical Skill</a></p></li><li><p><a href="https://www.thescalable.net/i/132827621/soft-skill-and-mindset">Soft Skill &amp; Mindset</a></p><ul><li><p><a href="https://www.thescalable.net/i/132827621/think-structurally">Think Structurally</a></p></li><li><p><a href="https://www.thescalable.net/i/132827621/problem-solver">Focus on Solve Problem</a></p></li><li><p><a href="https://www.thescalable.net/i/132827621/growth-mindset">Growth Mindset</a></p></li><li><p><a href="https://www.thescalable.net/i/132827621/positive">Positive Mindset</a></p></li></ul></li><li><p><a href="https://www.thescalable.net/i/132827621/behavior">Behavior</a></p><ul><li><p><a href="https://www.thescalable.net/i/132827621/eager-to-learn-pareto-principle">Eager to Learn</a></p></li><li><p><a href="https://www.thescalable.net/i/132827621/proactive-and-self-motivated">Proactive &amp; Self Motivated</a></p></li><li><p><a href="https://www.thescalable.net/i/132827621/good-ethics">Good Ethics &amp; Integrity</a></p></li></ul></li><li><p><a href="https://www.thescalable.net/i/132827621/tldr">TL;DR</a></p></li></ul><div><hr></div><h2>Intro</h2><p>A great junior software engineer is a software engineer who demonstrates qualities and potential for growth. This type of engineer simply needs a bit of direction, and they will quickly excel in terms of skills and career progression.</p><p>Whether as a co-worker or a leader, working with this type of engineer is pleasant for me. I don't need to put in much effort to make them functionally capable, and witnessing their growth is truly enjoyable.</p><p>I have interviewed 1k++ software engineers, and after conducting numerous interviews, I have noticed a pattern that distinguishes an average engineer from a potential software engineer.</p><p>In today's discussion, we are going to break down the characteristics and qualities of good junior software engineer looks like. We will explore the technical skills, soft skills, and behaviors needed for a software engineer with great potential.</p><h2>Technical Skill</h2><p>Having strong technical skills in the early stages of a software engineering career indeed helps, but it does not guarantee success. I have observed many individuals who excelled in university or were capable of writing good code, but when they entered the industry, they failed to make an impact on the company, and their skills and careers stagnated.</p><p>If you don't have strong technical skills, don't worry. At this stage, you are allowed to "Follow the rule first (framework or standard), then follow your heart." However, it's important to note that you still need a decent technical skill. At the very least, you should:</p><ol><li><p>Understand the fundamentals of algorithms and data structures. It's okay if you only <strong>know how to use them</strong>. Having a deeper understanding of how they work is even better.</p></li><li><p>Be proficient in <strong>at least one programming language</strong> and its associated <strong>frameworks</strong>. <br>Suggestion: focus on mastering one language first. When you already have a grasp you could learn more with the focus understanding end-to-end from frontend until your product deployed and can be accessed.</p></li><li><p>Be able to read logs, perform testing, debugging, and Googling (and Chat GPT-ing) to learn from problems.</p></li><li><p>Be able to work with MySQL or PostgreSQL, familiarizing yourself with database management and interacting with databases.</p></li></ol><h2>Soft Skill &amp; Mindset</h2><h4>Think Structurally</h4><p>Software engineering things revolve around thinking structurally. Algorithms involve step-by-step to solve a problem, which inherently follows a structure. Similarly, data structures, as the name suggests, are all about organizing and structuring data.</p><p>I have observed that software engineers with great potential always think structurally. It is easy to identify this quality by simply examining how they explain things and approach their work on projects.</p><p>When explaining things, they tend to provide explanations in a step-by-step manner, rather than jumping in and out of concepts. They organize their tasks structurally, for example developing "Create API" before the "Getter API" is important for them, because it helps them become more efficient in testing features and ensures a systematic progression in their work.</p><h4>Problem Solver</h4><p>An average software engineer: focus on completing tasks</p><p>A great junior software engineer: focus on solving the problems.</p><p>To illustrate this contrast, let's consider the scenario where an engineer is asked to build an API to display a transaction history.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Jy3D!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe46bdce0-91ca-48e8-977a-7eed5a83d6aa_1758x988.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Jy3D!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe46bdce0-91ca-48e8-977a-7eed5a83d6aa_1758x988.png 424w, https://substackcdn.com/image/fetch/$s_!Jy3D!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe46bdce0-91ca-48e8-977a-7eed5a83d6aa_1758x988.png 848w, https://substackcdn.com/image/fetch/$s_!Jy3D!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe46bdce0-91ca-48e8-977a-7eed5a83d6aa_1758x988.png 1272w, https://substackcdn.com/image/fetch/$s_!Jy3D!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe46bdce0-91ca-48e8-977a-7eed5a83d6aa_1758x988.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Jy3D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe46bdce0-91ca-48e8-977a-7eed5a83d6aa_1758x988.png" width="1456" height="818" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e46bdce0-91ca-48e8-977a-7eed5a83d6aa_1758x988.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:818,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:245186,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Jy3D!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe46bdce0-91ca-48e8-977a-7eed5a83d6aa_1758x988.png 424w, https://substackcdn.com/image/fetch/$s_!Jy3D!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe46bdce0-91ca-48e8-977a-7eed5a83d6aa_1758x988.png 848w, https://substackcdn.com/image/fetch/$s_!Jy3D!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe46bdce0-91ca-48e8-977a-7eed5a83d6aa_1758x988.png 1272w, https://substackcdn.com/image/fetch/$s_!Jy3D!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe46bdce0-91ca-48e8-977a-7eed5a83d6aa_1758x988.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>The software engineer that has a great potential will find out what is the real problem and how to solve it. In this scenario, writing code is not a problem, querying is not a problem, how to display the transaction is the problem.</p><h4>Growth Mindset</h4><p>A growth mindset is a belief system or mindset in which individuals believe that their abilities, intelligence, and talents can be developed and improved through effort, learning, and persistence.</p><p>Software engineers with great potential possess a growth mindset. They embrace challenges and constantly seek opportunities to review their mistakes and improve in the future. They are not afraid of feedback and actively seek ways to grow and develop their skills.</p><h4>Positive</h4><p>It's always easy to find faults in others or even within your own company. The larger the company, the higher the chance of encountering a "toxic group" of people who engage in negative conversations, leading to a detrimental atmosphere. Unfortunately, I have witnessed many potential software engineers who ended up joining such groups, resulting in a decline in their performance.</p><p>On the other hand, true software engineers with great potential, when they encounter something they dislike, choose to communicate with their superiors to clarify assumptions and find solutions. They approach these situations in a proactive and constructive manner.</p><h2>Behavior</h2><h4>Eager to Learn (20-80 Pareto Principle)</h4><p>I have observed that great junior software engineers share a common trait: they invest their time in developing their skills outside of working hours. This aligns with the Pareto principle, which suggests that 20% of the time spent outside of work can have an impact on 80% of their career development.</p><p>They often engage in personal projects, pursue learning courses, or go the extra mile for their company. This is what we refer to as being "eager to learn." However, the term can sometimes be vague. Many software engineers self-proclaim that they are eager to learn, but to clarify this, a simple question can be asked: "Could you explain what you have learned in the past 3 months?" This helps gauge their actual commitment to continuous learning and skill development. </p><h4>Proactive &amp; Self-Motivated</h4><p>Great junior software engineers possess a deep understanding that their success in their career is primarily dependent on their own efforts, rather than relying solely on others. As a result, they exhibit a proactive approach to acquiring knowledge and skills. They recognize the value of mentors, senior colleagues, and managers as valuable resources for growth and learning.</p><p>During one-on-one meetings, for instance, they take an active role in seeking feedback, guidance, and direction to enhance their impact within the team and the company. They actively participate in discussions, ask relevant questions, and demonstrate a genuine eagerness to improve.</p><p>Moreover, they exhibit a strong initiative in problem-solving. They don't wait for instructions or assignments; instead, they proactively identify and address challenges and seek solutions. These junior engineers willingly take on larger responsibilities when the opportunity arises, showing their readiness to contribute beyond their designated tasks.</p><h4>Good Ethics</h4><p>Many people possess various characteristics, but without good ethics, trust can be compromised, leading to a decline in professional relationships. Ultimately, trust is the most crucial aspect of one's career. When trust is established, it opens doors to opportunities, even if you may not be the most intelligent or skilled individual in the room.</p><h2>TL;DR</h2><p>So, being a great junior software engineer is not solely about technical proficiency. While they should possess a decent technical foundation, their soft skills and mindset play a significant role. These include structural thinking, a growth mindset, and a focus on problem-solving. Additionally, their behavior is instrumental in their growth, such as investing time to learn outside of working hours and being proactive.</p><p>Furthermore, they exhibit integrity and demonstrate positive ethics within the company. This involves acting in an ethical and principled manner, fostering trust and maintaining strong professional relationships. These qualities contribute to their overall success and growth as junior software engineers.</p><div><hr></div><p>That&#8217;s it for today, thank you for reading! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/how-does-a-great-junior-software?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/how-does-a-great-junior-software?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/how-does-a-great-junior-software/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/how-does-a-great-junior-software/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[User Friends System & Database Design]]></title><description><![CDATA[Social media user friend system and database design: User followers database design, 2-way friend list system design]]></description><link>https://www.coderbased.com/p/user-friends-system-and-database</link><guid isPermaLink="false">https://www.coderbased.com/p/user-friends-system-and-database</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Tue, 27 Jun 2023 08:14:28 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d374b69b-1223-40bb-9217-b3833078801e_1164x704.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to The Scalable, blog and newsletter to help you faster in becoming <em>tech leader</em>. Check our <a href="https://www.thescalable.net/p/tech-lead-roadmap">tech lead roadmaps</a>.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://twitter.com/herryg91">Twitter</a> &amp; <a href="https://www.linkedin.com/in/herryg91">Linkedin</a> and share this content to your friends. Enjoy.</p></blockquote><p>Quick Links:</p><ul><li><p><a href="https://www.thescalable.net/i/131171653/intro">Intro</a></p></li><li><p><a href="https://www.thescalable.net/i/131171653/user-followers-database-and-system-design">User Followers System &amp; Database Design (One-Way)</a></p></li><li><p><a href="https://www.thescalable.net/i/131171653/two-way-friend-system">Two-Way Friend System</a></p><ul><li><p><a href="https://www.thescalable.net/i/131171653/option-using-isapprove-column">Using is_approve Column</a></p></li><li><p><a href="https://www.thescalable.net/i/131171653/option-improved-version-adding-rule-userid-userid">Add rule UserID1 &lt; UserID2</a></p></li><li><p><a href="https://www.thescalable.net/i/131171653/option-double-row">Double Row</a></p></li></ul></li><li><p><a href="https://www.thescalable.net/i/131171653/conclusion">Conclusion</a></p></li></ul><div><hr></div><h2>Intro</h2><p>One important component of a social media feature is the friend system. Having a friend feature in your product fosters social interactions and enhances user experiences, which can lead to better engagement.</p><p>I categorize the friend system into two types:</p><ol><li><p>User Followers (one-way): This is a Twitter-like friend system.</p></li><li><p>Two-Way Friend: This is a Facebook and LinkedIn-like friend system.</p></li></ol><p>There are several components in friend systems, including:</p><ul><li><p>Adding friends</p></li><li><p>Approving or rejecting requests (depending on the use case)</p></li><li><p>Friend List</p></li><li><p>Friends of friends</p></li></ul><p>In today's article, we will discuss the system and database design of both types, and we will use MySQL or Postgres as the database. We will provide an overview of the user follower system and focus more on the two-way friend system. Additionally, we will specifically address the use case of adding friends and displaying the friend list.</p><h2>User Followers Database &amp; System Design</h2><p>In a user followers system, users can establish a one-way relationship where one user can follow another user without requiring mutual consent.</p><h4>Twitter User Followers System</h4><p>On Twitter, you can follow other users without their consent. The database design for this feature is relatively straightforward.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CANL!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4f068-d39f-42a2-adb2-854927e39fce_1966x1142.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CANL!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4f068-d39f-42a2-adb2-854927e39fce_1966x1142.png 424w, https://substackcdn.com/image/fetch/$s_!CANL!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4f068-d39f-42a2-adb2-854927e39fce_1966x1142.png 848w, https://substackcdn.com/image/fetch/$s_!CANL!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4f068-d39f-42a2-adb2-854927e39fce_1966x1142.png 1272w, https://substackcdn.com/image/fetch/$s_!CANL!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4f068-d39f-42a2-adb2-854927e39fce_1966x1142.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CANL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4f068-d39f-42a2-adb2-854927e39fce_1966x1142.png" width="1456" height="846" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/13f4f068-d39f-42a2-adb2-854927e39fce_1966x1142.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:846,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:191085,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CANL!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4f068-d39f-42a2-adb2-854927e39fce_1966x1142.png 424w, https://substackcdn.com/image/fetch/$s_!CANL!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4f068-d39f-42a2-adb2-854927e39fce_1966x1142.png 848w, https://substackcdn.com/image/fetch/$s_!CANL!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4f068-d39f-42a2-adb2-854927e39fce_1966x1142.png 1272w, https://substackcdn.com/image/fetch/$s_!CANL!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F13f4f068-d39f-42a2-adb2-854927e39fce_1966x1142.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Both option 1 and option 2 are relatively the same; it's just a matter of perspective. Personally, I prefer the first option because it's more intuitive for me.</p><h4>Instagram User Followers System</h4><p>On Instagram's following system, it's a bit different because you have the option to enable approvals. However, it is still considered a one-way relationship.</p><p>To solve this, we just need to add a new column: <code>is_approve</code> column.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Sy1i!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff909b1e4-8db9-41a9-8ba0-2bbf15119b9f_1814x810.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Sy1i!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff909b1e4-8db9-41a9-8ba0-2bbf15119b9f_1814x810.png 424w, https://substackcdn.com/image/fetch/$s_!Sy1i!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff909b1e4-8db9-41a9-8ba0-2bbf15119b9f_1814x810.png 848w, https://substackcdn.com/image/fetch/$s_!Sy1i!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff909b1e4-8db9-41a9-8ba0-2bbf15119b9f_1814x810.png 1272w, https://substackcdn.com/image/fetch/$s_!Sy1i!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff909b1e4-8db9-41a9-8ba0-2bbf15119b9f_1814x810.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Sy1i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff909b1e4-8db9-41a9-8ba0-2bbf15119b9f_1814x810.png" width="1456" height="650" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f909b1e4-8db9-41a9-8ba0-2bbf15119b9f_1814x810.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:650,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:156375,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Sy1i!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff909b1e4-8db9-41a9-8ba0-2bbf15119b9f_1814x810.png 424w, https://substackcdn.com/image/fetch/$s_!Sy1i!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff909b1e4-8db9-41a9-8ba0-2bbf15119b9f_1814x810.png 848w, https://substackcdn.com/image/fetch/$s_!Sy1i!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff909b1e4-8db9-41a9-8ba0-2bbf15119b9f_1814x810.png 1272w, https://substackcdn.com/image/fetch/$s_!Sy1i!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff909b1e4-8db9-41a9-8ba0-2bbf15119b9f_1814x810.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Two-Way Friend System</h2><p>In the two-way friend system, mutual consent is required to establish a friendship between two users. This is similar to the friend systems found in Facebook and LinkedIn.</p><p>Here is the general system design:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!WRyS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6c5715-f685-4953-aef4-1a8aed016716_1288x1058.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!WRyS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6c5715-f685-4953-aef4-1a8aed016716_1288x1058.png 424w, https://substackcdn.com/image/fetch/$s_!WRyS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6c5715-f685-4953-aef4-1a8aed016716_1288x1058.png 848w, https://substackcdn.com/image/fetch/$s_!WRyS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6c5715-f685-4953-aef4-1a8aed016716_1288x1058.png 1272w, https://substackcdn.com/image/fetch/$s_!WRyS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6c5715-f685-4953-aef4-1a8aed016716_1288x1058.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!WRyS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6c5715-f685-4953-aef4-1a8aed016716_1288x1058.png" width="416" height="341.7142857142857" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2a6c5715-f685-4953-aef4-1a8aed016716_1288x1058.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1058,&quot;width&quot;:1288,&quot;resizeWidth&quot;:416,&quot;bytes&quot;:176745,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!WRyS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6c5715-f685-4953-aef4-1a8aed016716_1288x1058.png 424w, https://substackcdn.com/image/fetch/$s_!WRyS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6c5715-f685-4953-aef4-1a8aed016716_1288x1058.png 848w, https://substackcdn.com/image/fetch/$s_!WRyS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6c5715-f685-4953-aef4-1a8aed016716_1288x1058.png 1272w, https://substackcdn.com/image/fetch/$s_!WRyS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2a6c5715-f685-4953-aef4-1a8aed016716_1288x1058.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h4>Option #1: Using <code>is_approve</code> Column</h4><p>Let's start with the first solution, where we use the same database design as <a href="https://www.thescalable.net/i/131171653/instagram-user-followers-system">Instagram's approval-based</a> one-way user followers system. The difference lies in how we query the data.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!3JY8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdea6e721-896c-4b48-ae3b-f983da3a12da_884x568.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!3JY8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdea6e721-896c-4b48-ae3b-f983da3a12da_884x568.png 424w, https://substackcdn.com/image/fetch/$s_!3JY8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdea6e721-896c-4b48-ae3b-f983da3a12da_884x568.png 848w, https://substackcdn.com/image/fetch/$s_!3JY8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdea6e721-896c-4b48-ae3b-f983da3a12da_884x568.png 1272w, https://substackcdn.com/image/fetch/$s_!3JY8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdea6e721-896c-4b48-ae3b-f983da3a12da_884x568.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!3JY8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdea6e721-896c-4b48-ae3b-f983da3a12da_884x568.png" width="330" height="212.03619909502262" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dea6e721-896c-4b48-ae3b-f983da3a12da_884x568.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:568,&quot;width&quot;:884,&quot;resizeWidth&quot;:330,&quot;bytes&quot;:33013,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!3JY8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdea6e721-896c-4b48-ae3b-f983da3a12da_884x568.png 424w, https://substackcdn.com/image/fetch/$s_!3JY8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdea6e721-896c-4b48-ae3b-f983da3a12da_884x568.png 848w, https://substackcdn.com/image/fetch/$s_!3JY8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdea6e721-896c-4b48-ae3b-f983da3a12da_884x568.png 1272w, https://substackcdn.com/image/fetch/$s_!3JY8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdea6e721-896c-4b48-ae3b-f983da3a12da_884x568.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Here are some notes you need to know to understand this schema:</p><ul><li><p><code>uid1</code> refers to the user who initiates a friend request</p></li><li><p><code>is_approve == false</code>, means the request is still pending</p></li><li><p><code>is_approve == true</code>, means both users have become friends.</p></li></ul><h6><strong>Add Friend Request</strong></h6><pre><code><code>// `id 10` add request to `id 15`
SELECT count(*) FROM user_friend 
WHERE (uid1 = 10 AND uid2 = 15) 
OR (uid1 = 15 AND uid2 = 10)

// If the result is 1, then the request has been made
// If the result is 0, then we could insert the request to the table
INSERT INTO user_friend (uid1, uid2, is_approve) 
VALUES (10, 15, false) </code></code></pre><h6>Retrieve Pending Friend Request</h6><pre><code><code>SELECT * FROM user_friend 
WHERE uid2 = 10 
AND is_approve is false</code></code></pre><h6>Retrieve Friend List</h6><pre><code><code>// use OR statement
SELECT * FROM user_friend 
WHERE (uid1 = 10 OR uid2 = 10) AND is_approve is true

// use UNION statement
SELECT * FROM user_friend WHERE uid1 = 10 AND is_approve is true
UNION ALL
SELECT * FROM user_friend WHERE uid2 = 10 AND is_approve is true</code></code></pre><h6>Approve / Reject</h6><pre><code><code>// Approve
UPDATE user_friend SET is_approve is true 
WHERE (uid1 = 10 AND uid2 = 15) 
OR (uid1 = 15 AND uid2 = 10)

// Reject
DELETE FROM user_friend 
WHERE (uid1 = 10 AND uid2 = 15) 
OR (uid1 = 15 AND uid2 = 10)</code></code></pre><p><strong>Advantage:</strong></p><ul><li><p>Easy to implement</p></li><li><p>Uses only 1 table</p></li></ul><p><strong>Disadvantage:</strong></p><ul><li><p>The retrieval query is not satisfactory.</p><ul><li><p>If using an OR query, it cannot be indexed.</p></li><li><p>If using UNION, sorting can be tricky.</p></li></ul></li><li><p>There is no guarantee that the data will not be duplicated (e.g., 10, 15 and 15, 10 are both possible)</p></li></ul><h4>Option #2: Improved version, adding rule UserID1 &lt; UserID2</h4><p>This is an improved version of the first option. It is similar but with an adjustment:</p><ul><li><p>Adding  the rule <code>uid1 &lt; uid2 </code></p></li><li><p>Changing the status to an enum</p><ul><li><p><code>REQ_UID1</code>: <code>uid1</code> makes a friend request to <code>uid2</code></p></li><li><p><code>REQ_UID2</code>: <code>uid2</code> makes a friend request to <code>uid1</code></p></li><li><p><code>FRIEND</code> means both users are friends</p></li></ul></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ph3M!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb29d6398-4efe-4e40-a996-2bc646182cbc_2362x722.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ph3M!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb29d6398-4efe-4e40-a996-2bc646182cbc_2362x722.png 424w, https://substackcdn.com/image/fetch/$s_!Ph3M!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb29d6398-4efe-4e40-a996-2bc646182cbc_2362x722.png 848w, https://substackcdn.com/image/fetch/$s_!Ph3M!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb29d6398-4efe-4e40-a996-2bc646182cbc_2362x722.png 1272w, https://substackcdn.com/image/fetch/$s_!Ph3M!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb29d6398-4efe-4e40-a996-2bc646182cbc_2362x722.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ph3M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb29d6398-4efe-4e40-a996-2bc646182cbc_2362x722.png" width="1456" height="445" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b29d6398-4efe-4e40-a996-2bc646182cbc_2362x722.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:445,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:115239,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!Ph3M!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb29d6398-4efe-4e40-a996-2bc646182cbc_2362x722.png 424w, https://substackcdn.com/image/fetch/$s_!Ph3M!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb29d6398-4efe-4e40-a996-2bc646182cbc_2362x722.png 848w, https://substackcdn.com/image/fetch/$s_!Ph3M!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb29d6398-4efe-4e40-a996-2bc646182cbc_2362x722.png 1272w, https://substackcdn.com/image/fetch/$s_!Ph3M!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb29d6398-4efe-4e40-a996-2bc646182cbc_2362x722.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h6><strong>Add Friend Request</strong></h6><pre><code>// `id 10` add request to `id 15`
INSERT INTO user_friend (uid1, uid2, status)
VALUES (10, 15, 'REQ_UID1');

// `id 10` add request to `id 4`
INSERT INTO user_friend (uid1, uid2, status)
VALUES (4, 10, 'REQ_UID2');</code></pre><h6>Retrieve Pending Friend Request</h6><pre><code>SELECT * FROM user_friend 
WHERE (uid1 = 10 AND status = 'REQ_UID2')
OR (uid2 = 10 AND status = 'REQ_UID1')

// OR using UNION

SELECT * FROM user_friend WHERE uid1 = 10 AND status = 'REQ_UID2'
UNION ALL
SELECT * FROM user_friend WHERE uid2 = 10 AND status = 'REQ_UID1'</code></pre><h6>Retrieve Friend List</h6><pre><code><code>SELECT * FROM user_friend 
WHERE (uid1 = 10 AND status = 'FRIEND')
OR (uid2 = 10 AND status = 'FRIEND')

// OR using UNION

SELECT * FROM user_friend WHERE uid1 = 10 AND status = 'FRIEND'
UNION ALL
SELECT * FROM user_friend WHERE uid2 = 10 AND status = 'FRIEND'</code></code></pre><h6>Approve / Reject</h6><pre><code>// Approve
UPDATE user_friend 
SET status = 'FRIEND' 
WHERE uid1 = 10 AND uid2 = 15

// Reject
DELETE FROM user_friend WHERE uid1 = 10 AND uid2 = 15</code></pre><p><strong>Advantages:</strong></p><ul><li><p>Easy to implement.</p></li><li><p>Intuitive, the data looks tidy.</p></li><li><p>Uses only 1 table.</p></li><li><p>Data is guaranteed not to duplicate.</p></li></ul><p><strong>Disadvantages:</strong></p><ul><li><p>The retrieval query still requires an <code>OR</code> or <code>UNION</code> statement</p></li></ul><h4>Option #3: Double Row</h4><p>This solution is implemented by creating duplicate rows, such as <code>AB</code> and <code>BA</code>. Users who have become friends will have two rows in the database.</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ml6r!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F449febb4-a9e1-4e0f-9c93-37b4debacae8_622x464.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ml6r!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F449febb4-a9e1-4e0f-9c93-37b4debacae8_622x464.png 424w, https://substackcdn.com/image/fetch/$s_!ml6r!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F449febb4-a9e1-4e0f-9c93-37b4debacae8_622x464.png 848w, https://substackcdn.com/image/fetch/$s_!ml6r!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F449febb4-a9e1-4e0f-9c93-37b4debacae8_622x464.png 1272w, https://substackcdn.com/image/fetch/$s_!ml6r!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F449febb4-a9e1-4e0f-9c93-37b4debacae8_622x464.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ml6r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F449febb4-a9e1-4e0f-9c93-37b4debacae8_622x464.png" width="252" height="187.9871382636656" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/449febb4-a9e1-4e0f-9c93-37b4debacae8_622x464.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:464,&quot;width&quot;:622,&quot;resizeWidth&quot;:252,&quot;bytes&quot;:20560,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" title="" srcset="https://substackcdn.com/image/fetch/$s_!ml6r!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F449febb4-a9e1-4e0f-9c93-37b4debacae8_622x464.png 424w, https://substackcdn.com/image/fetch/$s_!ml6r!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F449febb4-a9e1-4e0f-9c93-37b4debacae8_622x464.png 848w, https://substackcdn.com/image/fetch/$s_!ml6r!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F449febb4-a9e1-4e0f-9c93-37b4debacae8_622x464.png 1272w, https://substackcdn.com/image/fetch/$s_!ml6r!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F449febb4-a9e1-4e0f-9c93-37b4debacae8_622x464.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>To make this approach possible, we need to add a new table called <code>friend_request</code>. Let's check the design:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!E-6g!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64382fad-175c-447d-8dbc-c9098e7085b9_1976x500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!E-6g!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64382fad-175c-447d-8dbc-c9098e7085b9_1976x500.png 424w, https://substackcdn.com/image/fetch/$s_!E-6g!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64382fad-175c-447d-8dbc-c9098e7085b9_1976x500.png 848w, https://substackcdn.com/image/fetch/$s_!E-6g!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64382fad-175c-447d-8dbc-c9098e7085b9_1976x500.png 1272w, https://substackcdn.com/image/fetch/$s_!E-6g!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64382fad-175c-447d-8dbc-c9098e7085b9_1976x500.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!E-6g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64382fad-175c-447d-8dbc-c9098e7085b9_1976x500.png" width="1456" height="368" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/64382fad-175c-447d-8dbc-c9098e7085b9_1976x500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:368,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:52265,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!E-6g!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64382fad-175c-447d-8dbc-c9098e7085b9_1976x500.png 424w, https://substackcdn.com/image/fetch/$s_!E-6g!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64382fad-175c-447d-8dbc-c9098e7085b9_1976x500.png 848w, https://substackcdn.com/image/fetch/$s_!E-6g!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64382fad-175c-447d-8dbc-c9098e7085b9_1976x500.png 1272w, https://substackcdn.com/image/fetch/$s_!E-6g!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F64382fad-175c-447d-8dbc-c9098e7085b9_1976x500.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Notes:</p><ul><li><p>I suggest we use the rule of <code>uid1 &lt; uid2</code> for the <code>friend_request</code> table.</p></li><li><p>In the <code>requestor</code> column </p><ul><li><p><code>UID1</code>: if <code>uid1</code> is the one who initiate the friend request.</p></li><li><p><code>UID2</code>: if <code>uid2</code> is the one who initiate the friend request.</p></li></ul></li></ul><h6><strong>Add Friend Request</strong></h6><pre><code><code>// `id 10` add request to `id 15`
INSERT INTO friend_request (uid1, uid2, requestor) 
VALUES (10, 15, 'UID1')

// `id 10` add request to `id 4`
INSERT INTO friend_request (uid1, uid2, requestor) 
VALUES (4, 10, 'UID2')</code></code></pre><h6>Retrieve Pending Friend Request</h6><pre><code><code>SELECT * FROM friend_request 
WHERE (uid1 = 10 AND requestor = 'UID2') 
OR (uid2 = 10 AND requestor = 'UID1')</code></code></pre><h6>Retrieve Friend List</h6><pre><code><code>SELECT * FROM user_friend WHERE user_id = 10</code></code></pre><h6>Approve / Reject</h6><pre><code><code>// Approve
INSERT INTO user_friend (user_id, friend_id) VALUES (10, 15)
INSERT INTO user_friend (user_id, friend_id) VALUES (15, 10)
DELETE FROM friend_request 
  WHERE (uid1 = 10 AND uid2 = 15) 
  OR (uid1 = 15 AND uid2 = 10) 

// Reject
DELETE FROM friend_request 
  WHERE (uid1 = 10 AND uid2 = 15) 
  OR (uid1 = 15 AND uid2 = 10) </code></code></pre><p><strong>Advantages:</strong></p><ul><li><p>The data is tidy and intuitive.</p></li><li><p>Indexing can work effectively.</p></li></ul><p><strong>Disadvantages:</strong></p><ul><li><p>Data stored becomes duplicated.</p></li><li><p>The <code>friend_request</code> table acts as temporary data but is required to implement this design.</p></li></ul><h2>Conclusion</h2><p>There are many creative ways to solve the friend system. In the user follower friend system, such as a Twitter-like friend system, it is more straightforward, as we can simply match the <code>user_id</code> and <code>friend_id</code>.</p><p>In the two-way friend system, like the friend systems found in Facebook and LinkedIn, there are more options to choose from depending on your use case. Personally, I would suggest considering the <a href="https://www.thescalable.net/i/131171653/option-improved-version-adding-rule-userid-userid">2nd option</a> or the <a href="https://www.thescalable.net/i/131171653/option-double-row">3rd option</a>.</p><div><hr></div><p>Thank you for reading today's newsletter! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/user-friends-system-and-database?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/user-friends-system-and-database?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/user-friends-system-and-database/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/user-friends-system-and-database/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[Strong First 90 Days as Software Engineer]]></title><description><![CDATA[Building a strong first 90 days in a new job is important. This period for you to create a positive impression and establish trust, which plays a significant role in shaping your career growth]]></description><link>https://www.coderbased.com/p/strong-first-90-days-as-software</link><guid isPermaLink="false">https://www.coderbased.com/p/strong-first-90-days-as-software</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Tue, 20 Jun 2023 08:00:50 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/d2dc791b-b265-4c90-9177-27f511cc651a_1452x872.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to The Scalable, blog and newsletter to help you faster in getting promoted into <em>tech lead</em> position. We are release new content 1-2x a week.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://twitter.com/herryg91">Twitter</a> &amp; <a href="https://www.linkedin.com/in/herryg91">Linkedin</a> and share this content to your friends. Enjoy.</p></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p>Quick Links:</p><ul><li><p><a href="https://www.thescalable.net/i/129533948/intro">Intro</a></p></li><li><p><a href="https://www.thescalable.net/i/129533948/first-month-max-months-adapt">First Month: Adaptation</a></p><ul><li><p><a href="https://www.thescalable.net/i/129533948/do-one-on-one-alignment">Do One-on-One</a></p></li><li><p><a href="https://www.thescalable.net/i/129533948/gain-domain-knowledge">Gain Domain Knowledge</a></p></li><li><p><a href="https://www.thescalable.net/i/129533948/listen-and-observe-more">Listen and Observe</a></p></li><li><p><a href="https://www.thescalable.net/i/129533948/build-relation">Build Relation</a></p></li></ul></li><li><p><a href="https://www.thescalable.net/i/129533948/month-getting-involved-and-make-impression">Month 2-3: Getting Involved &amp; Make Impression</a></p><ul><li><p><a href="https://www.thescalable.net/i/129533948/proving-expectations">Proving Expectation</a></p></li><li><p><a href="https://www.thescalable.net/i/129533948/address-improvement">Address Improvement</a></p></li><li><p><a href="https://www.thescalable.net/i/129533948/take-more-responsibilities-help-others">Take More Responsibility</a></p></li></ul></li><li><p><a href="https://www.thescalable.net/i/129533948/tldr">TL;DR</a></p></li></ul><div><hr></div><h2>Intro</h2><p>People achieve great careers (and getting promotions) not only because of their skillfulness but also because they <strong>gain trust</strong>.</p><blockquote><p>This explains why sometimes crucial positions in a company are filled by individuals who may lack of skills.</p></blockquote><p>When you join a new company, the first 90 days (3-month probationary period) are crucial for building a positive impression. Creating a good impression leads to trust. When people trust you, it enables effective collaboration, reliability, and accountability, resulting in successful project outcomes and professional growth. Consequently, this positively impacts your career.</p><p>Conversely, if you fail during your first 90 days, it's likely that you leave a negative impression. Reversing a bad impression becomes much more challenging once it has been formed. It may create skepticism even when you perform well, which can hinder your career progression.</p><p>In today's article, I will discuss how to have a strong first 90 days, allowing you to make a positive impression and propel your career to new heights.</p><h2>First Month (Max 1.5 months): Adapt</h2><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!_qo-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c9c452-57d3-4ab5-98f2-a38b87a67f00_727x726.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!_qo-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c9c452-57d3-4ab5-98f2-a38b87a67f00_727x726.png 424w, https://substackcdn.com/image/fetch/$s_!_qo-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c9c452-57d3-4ab5-98f2-a38b87a67f00_727x726.png 848w, https://substackcdn.com/image/fetch/$s_!_qo-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c9c452-57d3-4ab5-98f2-a38b87a67f00_727x726.png 1272w, https://substackcdn.com/image/fetch/$s_!_qo-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c9c452-57d3-4ab5-98f2-a38b87a67f00_727x726.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!_qo-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c9c452-57d3-4ab5-98f2-a38b87a67f00_727x726.png" width="305" height="304.58046767537826" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/88c9c452-57d3-4ab5-98f2-a38b87a67f00_727x726.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:726,&quot;width&quot;:727,&quot;resizeWidth&quot;:305,&quot;bytes&quot;:24808,&quot;alt&quot;:&quot;Tuckman's stages of group development&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Tuckman's stages of group development" title="Tuckman's stages of group development" srcset="https://substackcdn.com/image/fetch/$s_!_qo-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c9c452-57d3-4ab5-98f2-a38b87a67f00_727x726.png 424w, https://substackcdn.com/image/fetch/$s_!_qo-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c9c452-57d3-4ab5-98f2-a38b87a67f00_727x726.png 848w, https://substackcdn.com/image/fetch/$s_!_qo-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c9c452-57d3-4ab5-98f2-a38b87a67f00_727x726.png 1272w, https://substackcdn.com/image/fetch/$s_!_qo-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F88c9c452-57d3-4ab5-98f2-a38b87a67f00_727x726.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">source: commons.wikimedia.org</figcaption></figure></div><p>In Tuckman's stages of group development, when you have just joined a new company, you are in the state of <strong>forming</strong>. Forming is the process of establishing the structure of the team. During this stage, members may feel uncertain and tend to avoid conflicts in order to be accepted into the group.</p><p>In this state, your focus is to <em><strong>learn</strong></em> and <em><strong>adapt</strong></em> to the environment. You need to be proactive and not expect others to adapt to you. Instead, adapt to others. </p><p>Here are some actions that you can follow to help you adapt well:</p><h4>Do one-on-one alignment</h4><p>It is important to align expectations because it often happens that you fail during your first 90-day probationary period due to having different expectations with your direct report, subordinates, and other co-workers.</p><p>Schedule one-on-one meetings with your direct reports to align goals and targets that need to be achieved.</p><p>If you are joining as a leader, it is essential to have a conversation with your subordinates. </p><ul><li><p>Assess their current state (whether they are happy or not)</p></li><li><p>Assess team dynamics</p></li><li><p>Inquire about preferred communication style</p></li><li><p>Inquire about bottlenecks</p></li></ul><h4>Gain Domain Knowledge</h4><p>Your goal is to become <strong>functionally capable</strong> of performing your job. This means that by the end of the month, you should have a comprehensive understanding of your working domain, such as:</p><ul><li><p>Familiarizing with the codebase,</p></li><li><p>Understand end-to-end technical and user flows,</p></li><li><p>Identify the users of the product</p></li><li><p>Gaining insights into how users interact with the product,</p></li><li><p>And more.</p></li></ul><p>Gaining your working domain knowledge is important because it will set the foundation for a strong performance in the second and third months.</p><p>Here are some tips:</p><ul><li><p><strong>Follow the rules:</strong></p><p>People generally hate changes, especially when you are new to the team. In the current state, your focus should be on following the existing rules, frameworks, code standardization, and tools that have been established. If there is something you are not satisfied with, make a note of it, but avoid making changes at this point.</p></li><li><p><strong>Read documentation:</strong></p><p>If your company has comprehensive documentation, take the time to study it. Asked to the existing employee if necessary.</p></li><li><p><strong>Read the code:</strong></p><p>Sometimes, reading the code provides a deeper understanding of how the product or features function. Personally, I find this to be particularly useful during my first week at a new company. Understanding the code helps me grasp the <strong>how it works</strong> both in technical and business.</p></li><li><p><strong>Experience the product as a user:</strong></p><p>Gain a different perspective by approaching the product or feature from the standpoint of a user, rather than solely as a software engineer. Ultimately, the users are the ones who interact with your product, so it is important to understand how they use it.</p></li></ul><h4>Listen and Observe More</h4><p>Adapting well to the company and team culture is another crucial aspect. It is best to listen and observe more than talking or giving suggestions. Through active listening and observation, you will gain insights into the company and team norms, what is considered acceptable or not, as well as their preferences and dislikes. This will contribute to building trust with your co-workers.</p><h4>Build Relation</h4><p>It is essential to establish friendly relationships with your co-workers. I highly recommend finding the influential individuals in your team, often referred to as the "group leaders" </p><p>This person is typically the leader or manager (not always). Engaging in conversations with them will help you understand the team dynamics, develop rapport, and identify key individuals who can offer guidance, support, and valuable insights for navigating the team and organization effectively. </p><p>Building trust with these influential individuals will also facilitate gaining trust from others in the team.</p><h2>Month 2 - 3: Getting Involved &amp; Make Impression</h2><p>After the first month, you are expected to have adapted well to the new environment. This is typically demonstrated by receiving <strong>more important projects</strong>, <strong>receiving positive feedback</strong>, and <strong>gaining the attention and respect</strong> of others.</p><p>During the second and third months (90 days), it's a showtime. According to Tuckman's stages of group development, it's time to transition from the Forming stage to the Storming stage. However, it's important not to rush and approach it with a softer, more collaborative approach. During this period, the key is to be <strong>highly involved and engaged</strong>.</p><p>Here's what you can do during this period:</p><h4>Proving Expectations</h4><p>During the first month, you received expectations from your superiors and colleagues (through one-on-one). Now it's time to prove those expectations. Typically, expectations revolve around delivering work on time and with accuracy. Ensure that you meet deadlines and deliver high-quality results. If necessary, go the extra mile to surpass expectations. Be honest about your strengths and weaknesses, and focus on demonstrating tangible results.</p><p>If you fail to exceed expectations during this period, it is likely that you have not fully adapted to the company or that there is a skill gap that needs to be addressed.</p><h4>Address Improvement</h4><p>You may want to make a list of areas that need improvement, whether they are: </p><ul><li><p>Technical (such as: tech stack),</p></li><li><p>Procedural (such as: efficient code review), </p></li><li><p>or even Related to team culture (such as: how to communicate in slack)</p></li></ul><p>It is now your opportunity to address these issues, discuss their impact, and propose solutions. </p><h4>Take More Responsibilities (Help Others)</h4><p>If you have already proven yourself and met expectations, it's time to take on additional responsibilities. Discover a list of tasks that go beyond your main job but are essential for the team. For example:</p><ul><li><p>Assisting the operations support team</p></li><li><p>Identifying and organizing bugs</p></li><li><p>Establishing standards</p></li><li><p>Updating documentation</p></li><li><p>And more</p></li></ul><p>Often, there are tasks that require extra hands and fall under the category of going the extra mile. Take the initiative to assume these responsibilities and contribute to the team's success.</p><p>Alternatively, if necessary, you can take over some of the tasks assigned to your direct reports. For instance, if your direct report is responsible for task breakdown, you can offer to take on that responsibility yourself.</p><h2>TL;DR</h2><p>In the first month (0-30 day), focus on adapting to your coworkers, teams, and company by aligning expectations and gathering knowledge.</p><p>In the 31-90 day period, prove yourself by meet (or even exceed) the expectations. Get involved, make a good impression by contributing to improvements, and take on more responsibilities.</p><p>By following these tips, you can leave a strong and lasting impression, which in turn builds trust. This will undoubtedly contribute to your career growth.</p><div><hr></div><p>Thank you for reading today's newsletter! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/strong-first-90-days-as-software?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/strong-first-90-days-as-software?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/strong-first-90-days-as-software/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/strong-first-90-days-as-software/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[Why Everyone is Getting Promoted but Me?]]></title><description><![CDATA[Answering Why Everyone is Getting Promoted but Me? fundamental of why software engineer getting promoted: internal factors and external factors]]></description><link>https://www.coderbased.com/p/why-everyone-is-getting-promoted</link><guid isPermaLink="false">https://www.coderbased.com/p/why-everyone-is-getting-promoted</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Tue, 13 Jun 2023 08:00:22 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/f7849baf-59e2-4ba9-848c-38d8b04b94f8_1342x770.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to The Scalable, blog and newsletter to help you faster in getting promoted into <em>tech lead</em> position. We are release new content 1-2x a week.</p><p>Before we start, kindly to subscribe, follow me on <a href="https://twitter.com/herryg91">Twitter</a> &amp; <a href="https://www.linkedin.com/in/herryg91">Linkedin</a> and share this content to your friends. Enjoy.</p></blockquote><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p>Quick Links:</p><ul><li><p><a href="https://www.thescalable.net/i/127896779/intro">Intro</a></p></li><li><p><a href="https://www.thescalable.net/i/127896779/internal-factors">Internal Factors</a></p><ul><li><p><a href="https://www.thescalable.net/i/127896779/dunning-kruger">Dunning-Kruger</a></p></li><li><p><a href="https://www.thescalable.net/i/127896779/you-are-not-making-an-impact">Not Making Impact</a></p></li><li><p><a href="https://www.thescalable.net/i/127896779/no-one-know-your-achievements">No One know your Achievements</a></p></li></ul></li><li><p><a href="https://www.thescalable.net/i/127896779/external-factors">External Factors</a></p><ul><li><p><a href="https://www.thescalable.net/i/127896779/no-open-position">No Open Position</a></p></li><li><p><a href="https://www.thescalable.net/i/127896779/its-hierarchy">It&#8217;s Hierarchy</a></p></li><li><p><a href="https://www.thescalable.net/i/127896779/company-budget">Company Budget</a></p></li></ul></li><li><p><a href="https://www.thescalable.net/i/127896779/tldr">TL;DR</a></p></li></ul><h2>Intro</h2><p><code>Why is Everyone Getting Promoted but Me?</code> I have met many software engineers who ask this question. They feel that it is difficult to get a promotion in a Software Engineering career (especially below senior level). The career journey of these individuals typically unfolds as follows:</p><ol><li><p>They join the company with high spirits and strive to become valuable assets.</p></li><li><p>1-2 years pass, and they start feeling that they should be getting promoted, but they aren't. The reasons given by the company and their managers are unsatisfactory.</p></li><li><p>More year pass,</p><ol><li><p>Some of them leave the company and go back to square one.</p></li><li><p>Others lose hope and accept their fate, becoming zombie engineers.</p></li><li><p>Some choose to stay but become toxic to the company.</p></li></ol></li></ol><div class="pullquote"><p>We've just lost a potentially great software engineer.</p></div><p>But, <strong>is it really difficult to get a promotion in a Software Engineering career?</strong> Or perhaps <strong>you just don't know how?</strong> I have also seen many people who easily get promotions, including those whom I mentored, helping them get promoted 4x in two years, from Mid Level to Staff level (equivalent to a tech lead and an entry-level engineering manager). Whats different?</p><p>In this article, we will discuss the fundamentals of why a software engineer gets promoted. I hope this will help you realize that growing your career requires a strategy. Essentially, I will break it down into two sections:</p><ul><li><p>Internal Factors. (<em>Please focus on this section)</em></p></li></ul><ul><li><p>External Factors.</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FVSm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67eacb75-53bb-401a-8606-9a521a7258e0_1286x1282.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FVSm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67eacb75-53bb-401a-8606-9a521a7258e0_1286x1282.png 424w, https://substackcdn.com/image/fetch/$s_!FVSm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67eacb75-53bb-401a-8606-9a521a7258e0_1286x1282.png 848w, https://substackcdn.com/image/fetch/$s_!FVSm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67eacb75-53bb-401a-8606-9a521a7258e0_1286x1282.png 1272w, https://substackcdn.com/image/fetch/$s_!FVSm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67eacb75-53bb-401a-8606-9a521a7258e0_1286x1282.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FVSm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67eacb75-53bb-401a-8606-9a521a7258e0_1286x1282.png" width="524" height="522.3701399688958" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/67eacb75-53bb-401a-8606-9a521a7258e0_1286x1282.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1282,&quot;width&quot;:1286,&quot;resizeWidth&quot;:524,&quot;bytes&quot;:242050,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!FVSm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67eacb75-53bb-401a-8606-9a521a7258e0_1286x1282.png 424w, https://substackcdn.com/image/fetch/$s_!FVSm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67eacb75-53bb-401a-8606-9a521a7258e0_1286x1282.png 848w, https://substackcdn.com/image/fetch/$s_!FVSm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67eacb75-53bb-401a-8606-9a521a7258e0_1286x1282.png 1272w, https://substackcdn.com/image/fetch/$s_!FVSm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F67eacb75-53bb-401a-8606-9a521a7258e0_1286x1282.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2>Internal Factors</h2><h4>1. Dunning Kruger</h4><p>The Dunning-Kruger effect is a psychological phenomenon that refers to the tendency of individuals with low ability and knowledge to overestimate their competence and believe they are more skilled and knowledgeable than they actually are.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5yCm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F776ab885-ac71-477f-9a1d-08496c2fbf10_1231x1024.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5yCm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F776ab885-ac71-477f-9a1d-08496c2fbf10_1231x1024.png 424w, https://substackcdn.com/image/fetch/$s_!5yCm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F776ab885-ac71-477f-9a1d-08496c2fbf10_1231x1024.png 848w, https://substackcdn.com/image/fetch/$s_!5yCm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F776ab885-ac71-477f-9a1d-08496c2fbf10_1231x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!5yCm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F776ab885-ac71-477f-9a1d-08496c2fbf10_1231x1024.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5yCm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F776ab885-ac71-477f-9a1d-08496c2fbf10_1231x1024.png" width="372" height="309.4459788789602" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/776ab885-ac71-477f-9a1d-08496c2fbf10_1231x1024.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1024,&quot;width&quot;:1231,&quot;resizeWidth&quot;:372,&quot;bytes&quot;:66192,&quot;alt&quot;:&quot;Dunning Kruger Effect&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Dunning Kruger Effect" title="Dunning Kruger Effect" srcset="https://substackcdn.com/image/fetch/$s_!5yCm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F776ab885-ac71-477f-9a1d-08496c2fbf10_1231x1024.png 424w, https://substackcdn.com/image/fetch/$s_!5yCm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F776ab885-ac71-477f-9a1d-08496c2fbf10_1231x1024.png 848w, https://substackcdn.com/image/fetch/$s_!5yCm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F776ab885-ac71-477f-9a1d-08496c2fbf10_1231x1024.png 1272w, https://substackcdn.com/image/fetch/$s_!5yCm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F776ab885-ac71-477f-9a1d-08496c2fbf10_1231x1024.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a><figcaption class="image-caption">Source: commons.wikimedia.org</figcaption></figure></div><p><strong>Real example:</strong> Remember when the early version of Chat GPT was released? Many people suddenly labeled themselves as AI experts.</p><p>The Dunning-Kruger effect can create a gap where an engineer may feel they deserve a certain position while others, including their managers, may hold a different opinion.</p><p><strong>Solution:</strong></p><ul><li><p>Be honest to yourself</p></li><li><p>Seek feedback</p></li><li><p>Always improve yourself both hard skills and soft skills. As you acquire more skills and knowledge, the effects of the Dunning-Kruger phenomenon will gradually diminish</p></li></ul><h4>2. You are not making an Impact</h4><p>You are not affected by the Dunning-Kruger effect and you are skilled in software engineering. Such as:</p><ul><li><p>You have completed numerous coding challenges, </p></li><li><p>Obtained a master's degree in computer science,</p></li><li><p>Your skills are respected by others. </p></li></ul><p>However, you still have not been promoted while your friend has. How could this be?</p><div class="pullquote"><p>Good Skills != Being Impactful</p></div><p>To understand more, let&#8217;s consider this case study:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!9rMH!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b214487-fa6f-4a82-9604-e42ecb60b99a_1604x522.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!9rMH!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b214487-fa6f-4a82-9604-e42ecb60b99a_1604x522.png 424w, https://substackcdn.com/image/fetch/$s_!9rMH!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b214487-fa6f-4a82-9604-e42ecb60b99a_1604x522.png 848w, https://substackcdn.com/image/fetch/$s_!9rMH!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b214487-fa6f-4a82-9604-e42ecb60b99a_1604x522.png 1272w, https://substackcdn.com/image/fetch/$s_!9rMH!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b214487-fa6f-4a82-9604-e42ecb60b99a_1604x522.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!9rMH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b214487-fa6f-4a82-9604-e42ecb60b99a_1604x522.png" width="1456" height="474" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2b214487-fa6f-4a82-9604-e42ecb60b99a_1604x522.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:474,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:162555,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!9rMH!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b214487-fa6f-4a82-9604-e42ecb60b99a_1604x522.png 424w, https://substackcdn.com/image/fetch/$s_!9rMH!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b214487-fa6f-4a82-9604-e42ecb60b99a_1604x522.png 848w, https://substackcdn.com/image/fetch/$s_!9rMH!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b214487-fa6f-4a82-9604-e42ecb60b99a_1604x522.png 1272w, https://substackcdn.com/image/fetch/$s_!9rMH!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2b214487-fa6f-4a82-9604-e42ecb60b99a_1604x522.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>If you are a startup company focused on rapidly releasing new products to achieve Product-Market Fit (PMF), wouldn't it make more sense to promote <code>SEB</code> instead of <code>SEA</code>?</p><p><strong>Solution:</strong></p><ul><li><p>Expand your domain knowledge and understand the company's business, recognizing how your skills can make an impact.</p></li><li><p>Be flexible and adaptable.</p></li><li><p>Identify the requirements for the position you aspire to. If there is an <a href="https://www.thescalable.net/p/engineering-rubric">engineering rubric</a> or framework available, refer to it for guidance.</p></li></ul><h4>3. No One know your Achievements</h4><p>Now that you have acquired sufficient skills and are making an impact in the company. What other reasons could be preventing your promotion? It's possible that your achievements are not being tracked, and you are unable to effectively communicate your accomplishments to others.</p><p>This type of situation often arises in larger companies where the decision-making process for promotions is more complex. .</p><ul><li><p>The manager may perceive the engineer as good but not quite good enough for a promotion.</p></li><li><p>The engineer may believe they have met the requirements and performed well, yet they are not getting promoted.</p></li><li><p>Both parties rely on assumptions. The engineer may only recall that they have done good work but forget the specific details. <br>Consequently, the engineer struggles to effectively communicate and provide an explanation of their achievements.</p></li></ul><p>There&#8217;s a gap here. But, is it you manager&#8217;s fault? It could be, but I believe that's a negative mindset. If you have a goal, it is also your responsibility to effectively communicate your accomplishments and the reasons why you deserve a promotion.</p><p><strong>Solution:</strong></p><ul><li><p>Document your achievements every time you complete projects or reach milestones. Don't wait for the performance review period.</p></li><li><p>Mapped your achievements with the requirements needed for the next level</p></li><li><p>Have dedicated sessions during 1:1 meetings to discuss your progress, seek feedback, and address any gaps more promptly.</p></li></ul><h2>External Factors</h2><p>Assuming you have already addressed all the internal factors, I would say you have resolved 80% of the issues that may be hindering your promotion. However, there are still external factors that can prevent you from being promoted. In this case, I recommend you to focus on <strong>how to respond</strong> <strong>the situation.</strong></p><h4>1. No Open Position</h4><p>This is a common situation that occurs in companies where you have to wait for your superior to resign in order to be promoted.</p><p>Let's get back to the fundamentals: "Why does a position exist?"</p><p>A position in a company is created when <strong>there is a job that needs to be done</strong>. From the company's perspective, if all positions are already filled, there is no need to add more people to the same position as it would result in having individuals who are not assigned any work or responsibilities.</p><p>That&#8217;s why company is more likely to seek an employee who fits the specific needs of role rather than hiring the best candidate in the industry.</p><p><strong>How you should response:</strong></p><ul><li><p>You can always create a new position if you can make the company realize that there is a job that needs to be done but <strong>has not been recognized</strong> yet. Focus on finding it</p></li><li><p><strong>Personal Story:</strong> </p><ul><li><p>I worked at Tokopedia, the largest e-commerce marketplace in Indonesia, as part of the discovery tribes, with a focus on enhancing product discovery for users. <br>During my time there, I developed a recommendation system, which was a novel concept at the time. This system had a significant impact on business metrics. As a result of this achievement, I was promoted to a team lead position and given the opportunity to recruit and build a team.</p></li></ul></li></ul><h4>2. It&#8217;s Hierarchy</h4><p>The typical career structure follows a <strong>hierarchy</strong>, where higher positions become <strong>increasingly scarce</strong>. It's natural that you are being compared to your peers in such a setting.</p><p>Both you and your superior are human, as are the other engineers. Subjectivity can arise when objectivity is no longer applicable, especially when there are two or more individuals vying for a promotion.</p><p><strong>Here's how you should respond to this situation:</strong></p><ul><li><p>Understand that your superior might have a difficult time making decisions.</p></li><li><p>Avoid comparing yourself to others.</p></li><li><p>Improve your relationships with other people, including your superiors. Be more open and actively build trust. This is an area that is often lacking among software engineers.</p></li><li><p>If you feel that you are more deserving of a promotion, take a moment to reconsider. It might be attributed to your achievements being untracked or your inability to effectively explain your story.</p></li></ul><h4>3. Company Budget</h4><p>I think this point is quite clear. The most challenging aspect is to have the company communicate these reasons to you.</p><p>If this situation arises, you have several ways to respond:</p><ul><li><p>If your company in hard situation:</p><ul><li><p>Don't be egoistic; you need to consider your company's situation</p></li><li><p>You can request the company to promote you formally with a delayed salary increment until they have more profit or funds available.</p></li><li><p>Continue to make a positive impact to contribute to the success of your company.</p></li></ul></li><li><p>However, if the reasons for not getting promoted are unrelated to the company's financial situation, there may not be much you can do about it.</p><ul><li><p>As a last resort, you may consider exploring opportunities with other companies. Don&#8217;t become toxic, maintain professionalism and explain your circumstances.</p></li></ul></li></ul><h2>TL;DR</h2><ul><li><p><strong>Focus on internal factors first:</strong> improve your hard skills and soft skills, align them with your company goals, and effectively brand yourself by showcasing your achievements.</p></li><li><p>Be aware that there are external factors to consider, such as the hierarchical structure, lack of open positions, and budget constraints within the company.</p><ul><li><p>Be honest with yourself.</p></li><li><p>Understand the perspectives of the company, your superiors, and managers.</p></li><li><p>Avoid comparing yourself to others.</p></li><li><p>Communicate effectively with decision makers or superiors about the external factors. It may be possible to find solutions or alternatives.</p></li></ul></li></ul><div><hr></div><p>Thank you for reading today's newsletter! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/why-everyone-is-getting-promoted?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/why-everyone-is-getting-promoted?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/why-everyone-is-getting-promoted/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/why-everyone-is-getting-promoted/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[Communication Techniques in Software Engineering]]></title><description><![CDATA[Tips & techniques in communication for software engineers including how to providing and gathering context]]></description><link>https://www.coderbased.com/p/communication-techniques-in-software</link><guid isPermaLink="false">https://www.coderbased.com/p/communication-techniques-in-software</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Fri, 09 Jun 2023 10:19:33 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/a96c4851-2df1-49ad-867d-dd6af08c2a6e_1086x850.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to The Scalable, blog and newsletter to help you faster in getting promoted to senior position. We are release new content 1-2x a week. </p><p>Before we start, kindly follow me on <a href="https://twitter.com/herryg91">Twitter</a> &amp; <a href="https://www.linkedin.com/in/herryg91">Linkedin</a> and share this content to your friends. Enjoy.</p></blockquote><p>Quick Links:</p><ul><li><p><a href="https://www.thescalable.net/i/126900011/providing-context">Providing Context</a></p><ul><li><p><a href="https://www.thescalable.net/i/126900011/provide-background-information">Provide background information</a></p></li><li><p><a href="https://www.thescalable.net/i/126900011/talk-in-their-languages">Talk in their languages</a></p></li><li><p><a href="https://www.thescalable.net/i/126900011/use-analogy">Use Analogy</a></p></li><li><p><a href="https://www.thescalable.net/i/126900011/use-visuals">Use Visual</a></p></li><li><p><a href="https://www.thescalable.net/i/126900011/ask-for-re-explanation">Ask to re-explain</a></p></li></ul></li><li><p><a href="https://www.thescalable.net/i/126900011/gathering-context">Gathering Context</a></p><ul><li><p><a href="https://www.thescalable.net/i/126900011/active-listening-and-observation">Active Listening &amp; Observation</a></p></li><li><p><a href="https://www.thescalable.net/i/126900011/breakdown-the-discussion-into-smaller-parts">Breakdown the Discussion into Smaller Parts</a></p></li><li><p><a href="https://www.thescalable.net/i/126900011/first-principle-thinking">First Principle Thinking</a></p></li><li><p><a href="https://www.thescalable.net/i/126900011/summarize-and-explain-the-result-that-comes-to-your-mind">Summarize</a></p></li></ul></li><li><p><a href="https://www.thescalable.net/i/126900011/grow-your-empathy">Grow Empathy</a></p></li><li><p><a href="https://www.thescalable.net/i/126900011/conclusion">Conclusion</a></p></li></ul><div><hr></div><p>Communication is an essential skill in software engineering. Efficient communication can result in <strong>better product quality</strong> and <strong>faster delivery</strong>. I have often observed that one distinct factor differentiating seniors from juniors is their communication skills. In my opinion, seniors tend to have good communication skills. One piece of evidence is that non-technical individuals often seek out seniors for assistance instead of directly approaching the engineer who developed the system. I have inquired about this and received responses such as, "<em>I don't understand what the junior is saying, so it's better for me to ask the senior and wait for them to sync up with their mentee</em>".</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uQ6a!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3b70b9f-6cd1-40b5-abac-c33fc603fd7c_874x468.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uQ6a!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3b70b9f-6cd1-40b5-abac-c33fc603fd7c_874x468.png 424w, https://substackcdn.com/image/fetch/$s_!uQ6a!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3b70b9f-6cd1-40b5-abac-c33fc603fd7c_874x468.png 848w, https://substackcdn.com/image/fetch/$s_!uQ6a!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3b70b9f-6cd1-40b5-abac-c33fc603fd7c_874x468.png 1272w, https://substackcdn.com/image/fetch/$s_!uQ6a!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3b70b9f-6cd1-40b5-abac-c33fc603fd7c_874x468.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uQ6a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3b70b9f-6cd1-40b5-abac-c33fc603fd7c_874x468.png" width="354" height="189.55606407322654" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a3b70b9f-6cd1-40b5-abac-c33fc603fd7c_874x468.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:468,&quot;width&quot;:874,&quot;resizeWidth&quot;:354,&quot;bytes&quot;:74015,&quot;alt&quot;:&quot;What is good communication&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="What is good communication" title="What is good communication" srcset="https://substackcdn.com/image/fetch/$s_!uQ6a!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3b70b9f-6cd1-40b5-abac-c33fc603fd7c_874x468.png 424w, https://substackcdn.com/image/fetch/$s_!uQ6a!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3b70b9f-6cd1-40b5-abac-c33fc603fd7c_874x468.png 848w, https://substackcdn.com/image/fetch/$s_!uQ6a!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3b70b9f-6cd1-40b5-abac-c33fc603fd7c_874x468.png 1272w, https://substackcdn.com/image/fetch/$s_!uQ6a!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa3b70b9f-6cd1-40b5-abac-c33fc603fd7c_874x468.png 1456w" sizes="100vw" fetchpriority="high"></picture><div></div></div></a></figure></div><p>But what does good communication mean in terms of software engineering? It certainly does not involve <em>sweet-talking</em> or <em>making empty promises</em> about features. In simple terms, good communication means ensuring mutual understanding between parties. It means that <em><strong>"I understand what you mean"</strong></em> and <em><strong>"You understand what I mean."</strong></em></p><p>From that definition, there are two components to having good communication:</p><ul><li><p>Being good at <strong>providing context</strong>.</p></li><li><p>Being good at <strong>gathering context</strong>.</p></li></ul><p>In <em>one-way communication</em> (sharing knowledge or ordered by superior) you might only need one component. However, in <em>two-way communication</em> (discussions), you definitely need both components.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PD4B!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf62365a-711f-4032-93a5-215a01304343_1668x1098.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PD4B!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf62365a-711f-4032-93a5-215a01304343_1668x1098.png 424w, https://substackcdn.com/image/fetch/$s_!PD4B!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf62365a-711f-4032-93a5-215a01304343_1668x1098.png 848w, https://substackcdn.com/image/fetch/$s_!PD4B!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf62365a-711f-4032-93a5-215a01304343_1668x1098.png 1272w, https://substackcdn.com/image/fetch/$s_!PD4B!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf62365a-711f-4032-93a5-215a01304343_1668x1098.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PD4B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf62365a-711f-4032-93a5-215a01304343_1668x1098.png" width="490" height="322.40384615384613" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/df62365a-711f-4032-93a5-215a01304343_1668x1098.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:958,&quot;width&quot;:1456,&quot;resizeWidth&quot;:490,&quot;bytes&quot;:239178,&quot;alt&quot;:&quot;Communication Techniques in Software Engineering&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Communication Techniques in Software Engineering" title="Communication Techniques in Software Engineering" srcset="https://substackcdn.com/image/fetch/$s_!PD4B!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf62365a-711f-4032-93a5-215a01304343_1668x1098.png 424w, https://substackcdn.com/image/fetch/$s_!PD4B!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf62365a-711f-4032-93a5-215a01304343_1668x1098.png 848w, https://substackcdn.com/image/fetch/$s_!PD4B!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf62365a-711f-4032-93a5-215a01304343_1668x1098.png 1272w, https://substackcdn.com/image/fetch/$s_!PD4B!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdf62365a-711f-4032-93a5-215a01304343_1668x1098.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>In today's article, we will discuss various tips and techniques to help you excel at <strong>providing and gathering context</strong>, depending on the individuals you are communicating with. In software engineering, you typically interact with four types of people: peers, superiors, subordinates, and non-technical individuals.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Scalable is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>Providing Context</h2><p>In communication, providing context means offering relevant information and ensuring that it is understood by the recipients, conveying the intended message clearly. If you often hear phrases like <em>"I don't understand what you mean",</em> it may indicate that you have not effectively provided the necessary context for others to comprehend.</p><p>This skill is incredibly important because a failure to do so can lead to discussions filled with <strong>assumptions</strong>, resulting in <strong>increased time</strong> to address problems, making <strong>incorrect decisions</strong> and taking <strong>inappropriate actions</strong>, among other issues.</p><p>Here are some communication techniques to improve your proficiency in providing context.</p><h4>Provide Background Information</h4><p><code>Use this in situation: All situation (except you have already intensely communication with the person about the topics)</code></p><p>I often met an engineers that jump into a discussion without considering whether the other party is prepared for the discussion or not. Like this conversation:</p><blockquote><p><strong>Engineer 1 (E1):</strong> Hi, please revert back your formula just for my case. My feature got bugs because of it.</p><p><strong>Engineer 2 (E2):</strong> Wait... What?</p></blockquote><p>Compare it with:</p><blockquote><p><strong>E1:</strong> Hey, currently, one of your codes is impacting my feature, which is <code>Feature A</code> that has dependency to your <code>endpoint X</code>. It seems like you have implemented a new formula, but in my case, I still need the old formula. Can you implement a condition when my feature hits your endpoints?</p></blockquote><p>Whether you are talking to fellow engineer or even non-tech person, it is important to provide the necessary background information. This includes explaining the situation, goals or problems, relevant information about the topic, and the rationale behind your decision.</p><p>By providing this context, you enable your audience to understand the current situation and make informed judgments.</p><h4>Talk in their languages</h4><p><code>Use this in situation: All situation</code></p><p>I have written a brief about this in the article, which you can check out <a href="https://www.thescalable.net/i/122698682/improve-communication-speak-their-language">here</a>. In the article, I provide an example of how Tyrion Lannister from Game of Thrones is able to adapt and communicate effectively with different individuals.</p><pre><code>Notes: Here, <strong>"languages"</strong> does not refer to English, French, or other spoken languages, but rather to the level or style of communication that can be understood by the other party.</code></pre><p>A good communicator is able to adjust their language level, sometimes toning it down, changing their words, talking around the topic, or being straightforward, depending on the person they are speaking to.</p><blockquote><p>Business Guy <strong>(B)</strong>: Our user asked if we can do custom calculations for the tax.</p><p>Software Engineer <strong>(SE)</strong>: I think it's difficult to implement that. All of our functions already rely on the current fixed calculations stored in our database.</p></blockquote><p>Compared with:</p><blockquote><p><strong>B</strong>: Our user asked if we can do custom calculations for the tax.</p><p><strong>SE</strong>: Didn't we agree in the past that custom calculations were not allowed due to government policy? Has there been any change? Have you researched this?</p></blockquote><p>See the differences? If you are a fellow engineer, you might understand the first conversation. However, if you don't fully grasp the context and domain knowledge, the second conversation might be easier to understand</p><p>It may not be easy to communicate in a language that the other person understands, but you can follow these tips:</p><ul><li><p><strong>Research and understand the audience:</strong> Consider the background, knowledge, and expertise of your audience. You may need to familiarize yourself with the domain knowledge that your audience understands, including the terms and phrases they are familiar with.</p></li><li><p><strong>Avoid technical jargon:</strong> Steer clear of jargon and technical terms, especially when communicating with non-technical stakeholders. Provide explanations when necessary. While using tech jargon looks cool, it often contributes to the perception of "bad communication" among engineers. Use technical jargon only if you are 100% sure that the other party already understands it (typically when communicating with peers).</p></li><li><p><strong>Experiment and adapt</strong>: It may not be easy to determine the appropriate level of communication that will be well-received by both parties. You can try using a specific language level and, if the other party doesn't understand, adjust your approach accordingly.</p></li></ul><h4>Use Analogy</h4><p><code>Use this in situation: Mainly when converse with non-tech</code></p><p>You might encounter situations where it is challenging to find sentences that your audience can easily understand. In such cases, you can use analogies that are similar to the situation at hand to explain things, enabling the other party to grasp and visualize the concepts more easily.</p><p>Let's learn through an example:</p><blockquote><p><strong>Non-Tech Guy:</strong> Hey, tomorrow we are going to have a big event, and we expect the traffic to increase 5x. It should be easy to handle, right? Just make your server bigger.</p><p><strong>Software Engineer:</strong> It's not that simple. Imagine you are running a restaurant with a capacity for only 20 people. Suddenly, you have 100 people waiting in line. It's not just a matter of expanding the physical space; you also need to hire more cooks, waiters, stock up on additional raw materials for food, maybe even pre-prepare some dishes so the chef can cook them upon order, and so on.</p></blockquote><p>By using this analogy, it becomes much simpler for the non-tech person to understand the situation compared to explaining concepts such as horizontal scaling, caching, load balancers, and more.</p><p>This technique can still be used to communicate with fellow engineers, but you can utilize analogies related to technical concepts. Personally, I rarely use this technique with fellow engineers.</p><h4><strong>Use Visuals</strong></h4><p><code>Use this in situation: Explaining something hard to explain such as system design</code></p><p>Communication is not limited to verbal expression alone. Non-verbal communication, including the use of visuals, plays an important role. While visuals may not be suitable for every discussion, I highly recommend utilizing them when possible. </p><div class="pullquote"><p>Visual says thousands words </p></div><p>I usually employ this technique when communicating with my subordinates (mentees), especially when explaining system design. Utilizing charts or mind maps proves to be very helpful. I rarely discuss this with the managerial level and above, as we typically have a mutual understanding through verbal communication at a higher conceptual level.</p><p>Apart from that, when engaging in conversations with non-technical individuals, I frequently utilize this method in certain cases, such as providing infographics.</p><h4><strong>Ask for Re-explanation</strong></h4><p><code>Use this in situation: Converse with your mentee</code></p><p>Remember, the purpose of providing context is to ensure that your audience truly understands your message. However, there is often a bias where people think they understand, but in reality, they have misunderstood. To address this, you can ask them to re-explain the concept using their own words to ensure that both of you are on the same page.</p><blockquote><p>"For clarity, can you please explain in your own words what I've just explained and let me know what actions you need to take?"</p></blockquote><p>You can also summarize the conversation to double-check if both parties are aligned and have a shared understanding.</p><div class="captioned-button-wrap" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/communication-techniques-in-software?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="CaptionedButtonToDOM"><div class="preamble"><p class="cta-caption">Thank you for reading The Scalable. This post is public so feel free to share it.</p></div><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/communication-techniques-in-software?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/communication-techniques-in-software?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p></div><h2>Gathering Context</h2><p>Gathering context (in communication) is the process of <strong>actively seeking</strong> and <strong>acquiring relevant information</strong> in order to understand the intentions or messages of others. With good context-gathering skills, your communication becomes much more efficient because you can respond with relevant messages. </p><p>Let me provide you with a real-world example (which actually happened) of a situation where a software engineer was poor at gathering context.</p><pre><code><strong>Background Story:</strong>
- In the e-commerce industry, a product manager asks a junior software engineer to <strong>display transaction statuses</strong> on the website.
- In the database, there are already six transaction statuses: <strong>PENDING</strong>, <strong>VERIFYING</strong>, <strong>PROCESSING</strong>, <strong>DELIVERY</strong>, <strong>DONE</strong>, <strong>FAILED</strong>.</code></pre><p>The conversation goes as follows:</p><blockquote><p><strong>Product Manager (PM):</strong> Hey JE, for our next project, we need to <strong>show transaction statuses</strong> in the user transaction history. Our users often inquire about the delivery status.</p><p><strong>Junior Engineer (JE):</strong> So, I just need to display the 6 transaction statuses, right? Where exactly should I put them?</p><p><strong>PM:</strong> Yes. You know, on the history page, below the total amount, there's a blank space. Just add a badge with the statuses inside it.</p><p><strong>JE:</strong> Alright, I'll do it right away.</p><p><strong>PM:</strong> How long will it take?</p><p><strong>JE:</strong> Two days.</p></blockquote><p>The product manager didn't create a requirement document because he believed it was just a matter of displaying the status, and other competitor companies have similar statuses implemented well. However, the result turned out to be far from what the product manager expected:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TmbD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b8b308a-3de1-48b1-a337-ce6321b0ea42_1002x658.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TmbD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b8b308a-3de1-48b1-a337-ce6321b0ea42_1002x658.png 424w, https://substackcdn.com/image/fetch/$s_!TmbD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b8b308a-3de1-48b1-a337-ce6321b0ea42_1002x658.png 848w, https://substackcdn.com/image/fetch/$s_!TmbD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b8b308a-3de1-48b1-a337-ce6321b0ea42_1002x658.png 1272w, https://substackcdn.com/image/fetch/$s_!TmbD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b8b308a-3de1-48b1-a337-ce6321b0ea42_1002x658.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TmbD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b8b308a-3de1-48b1-a337-ce6321b0ea42_1002x658.png" width="424" height="278.43512974051896" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6b8b308a-3de1-48b1-a337-ce6321b0ea42_1002x658.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:658,&quot;width&quot;:1002,&quot;resizeWidth&quot;:424,&quot;bytes&quot;:118532,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TmbD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b8b308a-3de1-48b1-a337-ce6321b0ea42_1002x658.png 424w, https://substackcdn.com/image/fetch/$s_!TmbD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b8b308a-3de1-48b1-a337-ce6321b0ea42_1002x658.png 848w, https://substackcdn.com/image/fetch/$s_!TmbD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b8b308a-3de1-48b1-a337-ce6321b0ea42_1002x658.png 1272w, https://substackcdn.com/image/fetch/$s_!TmbD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b8b308a-3de1-48b1-a337-ce6321b0ea42_1002x658.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Of course, the product manager is not 100% right in this situation, but I want to focus on the software engineer instead of the product manager. Instances like this often occur where the engineer lacks domain knowledge and misunderstands, leading to a failure in grasping what the PM truly means and consequently working on incorrect requirements.</p><blockquote><p>Note: The situation worsens when the engineer fails to gather any context and relies solely on assumptions.</p></blockquote><p>So, here are some tips and techniques for gathering context to prevent occurrences like this.</p><h4><strong>Active Listening &amp; Observation</strong></h4><p><code>Use this in situation: All situation</code></p><p>Engage in active listening by paying close attention to what others are saying (including small details). Focus on understanding their perspectives, concerns, and goals. Avoid interrupting and ask clarifying questions to ensure a thorough comprehension of the context being shared.</p><p>The purpose of active listening and observing your audience is to understand their main goal or point from the conversation. When you understand their goal or what they want, it becomes easier for you to respond effectively.</p><h4><strong>Breakdown the Discussion into Smaller Parts</strong></h4><p><code>Use this in situation: Have long &amp; unstructured explanation</code></p><p>Often, when trying to gather context, you may receive long and unstructured explanations. In such situations, you need to intervene and structure the conversation. One suggestion is to break down the discussion into smaller parts. Here's an example:</p><blockquote><p><strong>S. Engineer (SE):</strong> Could you please explain the...</p><p><strong>Product Manager (PM):</strong> So, the user flow starts with the user creating a loan request, and then the request will be curated by the superiors before...</p><p><strong>SE:</strong> Sorry for interrupting, but let's focus on the first step, which is creating the loan request, before we proceed to the next discussion.</p></blockquote><p>Breaking down the conversation into smaller parts allows for better focus when gathering context.</p><h4><strong>First Principle Thinking</strong></h4><p><code>Use this in situation: conversing with non-tech or geek engineers who use terms you don't understand and/or encounter ambiguity (something that makes you assuming things)</code></p><p>First principle thinking involves questioning every assumption you think you know about a given problem and creating new solutions from scratch. In first principle thinking, you question assumptions until they cannot be broken down any further.</p><p>In the example above, where the junior engineer built something that the PM didn't intend, there was ambiguity regarding the term <strong>"status".</strong> From the engineer's perspective, it referred to a status stored in the database, while in the PM's mind, it was about a status that the end user should understand. The problem arose because the engineer <strong>assumed</strong> the definition of "status" in technical terms.</p><p>In short, when you have any assumptions, clarify them right away. If there are terms you don't understand, ask until you gain a clear understanding.</p><h4><strong>Summarize &amp; Explain the Result that Comes to Your Mind</strong></h4><p><code>Use this in situation: converse with non-tech individual and/or mentee</code></p><p>Similar to "asking for re-explanation" in providing context, summarizing and explaining the result helps ensure that your understanding aligns with the other party's.</p><blockquote><p>"Hey, let me summarize today's discussion, and please correct me if I'm wrong..."</p></blockquote><p>This approach serves as a double-check to prevent miscommunication and ensure that both parties are on the same page.</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.thescalable.net/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share&quot;,&quot;text&quot;:&quot;Share The Scalable&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.thescalable.net/?utm_source=substack&amp;utm_medium=email&amp;utm_content=share&amp;action=share"><span>Share The Scalable</span></a></p><div><hr></div><h2><strong>Grow Your Empathy</strong></h2><p>I have already provided you with some tips and techniques to improve your communication through providing and gathering context. However, there are many more techniques and tips beyond that. If you carefully examine them, you will there is a factor that serves as the foundation for the techniques I shared with you.</p><p>That factor is <strong>empathy</strong>.</p><p>Empathy is the ability to understand and share the feelings of others as if you were in their own shoes. All the techniques are related to the empathy, but it can be challenging to explain how to cultivate empathy. That's why I provided you with the techniques directly. </p><p>Let&#8217;s save about empathy in software engineering for another topics.</p><div><hr></div><h2><strong>Conclusion</strong></h2><p>Effective communication is not a simple task. Throughout this article, I have provided you with tips and techniques to improve your communication skills. However, it is important to understand that communication is more than just exchanging information. Merely knowing about communication techniques does not automatically make you proficient in communication. It requires practice and consistent effort since communication skills are spontaneous and need daily practice. So, learn these skills, put them into practice, and you will undoubtedly become a better communicator.</p><div><hr></div><p>Thank you for reading today's newsletter! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/communication-techniques-in-software?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/communication-techniques-in-software?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/communication-techniques-in-software/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/communication-techniques-in-software/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[What is Senior Software Engineer? (My Standard)]]></title><description><![CDATA[What is Senior Software Engineer? What makes a Senior Software Engineer? What skills, knowledge and capabilities required? What are the roles and responsibilities?]]></description><link>https://www.coderbased.com/p/what-is-senior-software-engineer</link><guid isPermaLink="false">https://www.coderbased.com/p/what-is-senior-software-engineer</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Tue, 06 Jun 2023 08:06:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!6VC8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Welcome to The Scalable, blog and newsletter to help you faster in getting promoted to senior position. We are release new content 1-2x a week. Today we are going to discuss about the definition of Senior Engineer which very important before you make strategy.</p><p>Before we start, kindly follow me on <a href="https://twitter.com/herryg91">Twitter</a> &amp; <a href="https://www.linkedin.com/in/herryg91">Linkedin</a> and share this content to your friends. Enjoy.</p></blockquote><p>Quick Links:</p><ul><li><p><a href="https://www.thescalable.net/i/126339895/so-what-is-senior-software-engineer">What is Senior Software Engineer?</a></p></li><li><p><a href="https://www.thescalable.net/i/126339895/what-makes-a-senior-software-engineer">What makes a Senior Software Engineer?</a></p></li><li><p><a href="https://www.thescalable.net/i/126339895/what-are-the-roles-and-responsibilities-of-senior-software-engineer">Roles &amp; Responsibility</a></p></li></ul><div><hr></div><p>The Scalable is a newsletter where we discuss how to advance to the Senior Level (including positions such as Senior Software Engineer, Tech Lead, and hands-on Engineering Manager). Many of you may aspire to reach the senior level in your careers. However, before you start planning or taking action, the first thing you need to do is define <strong>&#8220;what is Senior Software Engineers?&#8221;</strong>. It can vary because different companies have different standards. But, do you aim for the senior level solely for the title, or do you want to become a senior in both title and quality/capability?</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6VC8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6VC8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png 424w, https://substackcdn.com/image/fetch/$s_!6VC8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png 848w, https://substackcdn.com/image/fetch/$s_!6VC8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png 1272w, https://substackcdn.com/image/fetch/$s_!6VC8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6VC8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png" width="1186" height="834" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/f3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:834,&quot;width&quot;:1186,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:134451,&quot;alt&quot;:&quot;What is Senior Software Engineer&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="What is Senior Software Engineer" title="What is Senior Software Engineer" srcset="https://substackcdn.com/image/fetch/$s_!6VC8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png 424w, https://substackcdn.com/image/fetch/$s_!6VC8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png 848w, https://substackcdn.com/image/fetch/$s_!6VC8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png 1272w, https://substackcdn.com/image/fetch/$s_!6VC8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff3474c62-8247-405e-9c6e-0f812f10d359_1186x834.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>When you obtaining the senior level but only the title, don&#8217;t assume that it&#8217;s without consequences. I've seen many people ruin their careers because their inflated titles do not match their capabilities. In the post-COVID era, where there have been significant tech layoffs, many senior and even management-level professionals are finding it difficult (at least in my country) to secure new jobs because they are overpaid and have inflated titles. There's a disconnect where employees feel like they're "ex-Unicorn A or ex-Unicorn B," but the new hiring company doesn't believe their capabilities will benefit the company.</p><p>In today's article, we will discuss my standards for defining what a Senior Software Engineer is, so you don't fall into the trap of title inflation.</p><h2>So, What is Senior Software Engineer?</h2><p>If someone asks me what a senior software engineer is, then my answer would be <strong>delivery</strong> and <strong>independence</strong>.</p><p><strong>Delivery</strong> means that a senior software engineer consistently produces good results within a relatively short time frame. It's important to note that delivery is not just about writing code; it can encompass various aspects, for example:</p><ul><li><p>Asking the right questions to shape and refine scope and requirements, minimizing errors and unnecessary work.</p></li><li><p>Choosing the appropriate technology to save time while achieving satisfactory results, especially from a business perspective.</p></li><li><p>If you're a lead or manager with subordinates, your presence should enhance the development process, making it more efficient and effective. </p></li><li><p>And more...</p></li></ul><p><strong>Independence</strong> (or autonomy) means understanding your role within the company and not relying on others to enable your performance. While having peers and superiors for discussion is valuable, you don't require constant micro-management. You do whatever it takes to ensure successful delivery. Although you may not make final decisions, you consistently provide options and influence the decision-making process.</p><h2>What makes a Senior Software Engineer?</h2><p>Now that we understand that being at the Senior Level is about <strong>delivery</strong> and <strong>independence</strong>, but it's still too broad to fully comprehend what truly makes someone a senior software engineer. To gain a deeper understanding, we need to break down the skills, knowledges and capabilities that support "delivery" and "independence" because I believe both of these qualities are a result of other skills, knowledges and capabilities.</p><h4>Fundamental Skills</h4><p>Undoubtedly, a solid foundation in software engineering is essential for every software engineer, especially at the senior level. This includes <strong>proficiency</strong> in programming languages, frameworks, code quality, databases, and more. </p><p>What sets senior-level engineers apart is their comprehensive understanding of the fundamentals for every technology and decision they make, as well as their ability to effectively implement them. For example, while a junior-level engineer may grasp the importance of indexing in a database, a senior-level engineer comprehends the intricacies of how indexing works, knows when it should and should not be implemented, and understands the potential side effects involved.</p><h4>System Design</h4><p>Senior software engineers possess the skills to design scalable, efficient, and maintainable software systems. </p><p>They understand different architectural patterns and can make informed decisions regarding the appropriate architecture for a given project. </p><p>They can analyze business requirements and translate them into technical solutions and system designs. They always consider the long-term relevance of the chosen design.</p><h4>Balancing Design and Implementation Trade-Offs</h4><p>Software engineering involves making trade-offs. While a good design often leads to a longer implementation time, a poor design may result in a quicker implementation. Senior-level engineers have the ability to assess options and understand the trade-offs when making decisions. They are pragmatic enough to consider both design and implementation trade-offs, sometimes sacrificing idealism for the sake of the company. If they are forced to make a poor design choice, they have strategies in place to improve it in the future.</p><h4>Domain Knowledge</h4><p>Senior-level engineers have a deep understanding of the domain specific to the industry or field in which they work. Combining technical proficiency with domain knowledge sets them apart from other software engineers. They no longer struggle with writing code but instead focus on aligning business and technical aspects.</p><p>If they are new to an industry, they are capable of independently acquiring the necessary knowledge specific to that domain. Consequently, they continuously expand their knowledge to effectively address the unique challenges and requirements of their industry.</p><p>Senior-level engineers often become the go-to person for domain-specific knowledge. For example, some of my friends who work at HR Tech companies even have a better understanding of their country's tax calculations than tax consultants</p><h4>Communication</h4><p>Senior software engineers collaborate with cross-functional teams, including product managers, designers, and quality assurance engineers. They possess excellent communication skills and can effectively convey technical concepts to both technical and non-technical stakeholders.</p><p>They can position themselves appropriately when communicating with non-technical person, technical leaders, or even mentees. They adjust their communication style to ensure the message is well received. They understand what to communicate and what questions to ask to unblocked the blockers and ensure successful delivery.</p><h4>Project Management and Time Management:</h4><p>Senior-level engineers excel in self-management, including time and task management. They can translate business requirements into technical requirements and break them down into smaller tasks. They accurately estimate timelines and prioritize tasks to prevent bottlenecks.</p><p>For roles such as tech lead and engineering manager, they can leverage their team members' skills to ensure projects run smoothly without bottlenecks. This is why having senior-level engineers on a team results in 1+1=5 not 1+1 = 2.</p><h4>People Management:</h4><p>In simple terms, at the senior level, you need to empower other team members, including mid-level and junior engineers. In most companies, there are typically two career paths for software engineers: the Individual Contributor Path (Pure Senior Software Engineer) and the Managerial Path, such as becoming a tech lead (a role that blends technical and managerial responsibilities) or an engineering manager (a purely managerial role).</p><p>The main difference lies in the fact that pure Senior Software Engineers may not require advanced people management skills. They primarily focus on being the go-to person to assist in the growth and improvement of other team members. They provide insights rather than direct answers, enabling others to develop. They may also delegate tasks to promote knowledge sharing and prevent siloed knowledge.</p><p>However, if you chooses to pursue the tech lead or managerial path, more advanced people management skills become essential. In these roles, being actively involved in people management is necessary, including conducting regular one-on-one meetings and creating growth plans for mid-level and junior engineers.</p><h4>Contribution</h4><p>Senior-level engineers always contribute in many ways, such as providing ideas for tech planning and project planning. They also contribute to code standardization, establishing standard procedures, and more. They go beyond simply writing code and actively contribute to making the work more efficient. </p><p>I have observed that some senior-level engineers are quite vocal and assertive, while others may be more reserved. However, regardless of their communication style, they consistently contribute in their own unique ways. Sometimes, even in meetings, they may voice out just one idea, but it proves to be on point. Whether one is outspoken or reserved, the measure of becoming a senior software engineer can be tracked by the level of contribution one makes.</p><h4>Debugging Skills</h4><p>Senior-level engineers always think ahead to prevent bugs by leveraging their technical proficiency and other knowledge. However, when a bug does occur, they are adept at identifying potential causes based on symptoms, debugging the issue, finding the root cause, and solving it with minimal information, often derived from logs. Their focus extends beyond solving the immediate bug; they also ensure that it does not recur in the future.</p><h2>What are the Roles and Responsibilities of Senior Software Engineer</h2><p>To answer the question of "what are the roles and responsibilities of a senior software engineer," it may vary across different companies. However, I can provide some common aspects that define the role of a senior software engineer:</p><p>One could say that a senior engineer is like a <strong>machine</strong> or <strong>driving force</strong> within the company. Therefore, it is likely that you will still need to be hands-on and actively involved in various tasks. Your main responsibility is to do whatever it takes, utilizing your skills and leveraging other team members, to deliver projects on time without constant supervision. As a senior software engineer, you should have a clear understanding of your role within the company.</p><p>Additionally, it is crucial to be an <strong>expert in at least one domain</strong> that is significant to the company. If you lack expertise in a specific domain, it is important to evaluate whether you are truly meeting the expectations of a senior-level role. To grasp the concept of domain expertise, consider the following example: In an e-commerce company, there are several domains that hold importance, such as search, product pages, transactions, ads and promotions, and more.</p><div><hr></div><p>So, that's it for today. Defining a senior engineer is challenging, and every company has different standards. However, with the guidelines provided in this article, you can establish your own standard and avoid getting caught up in title inflation. If you are currently facing title inflation, this will help you identify areas that need improvement.</p><div><hr></div><p>Thank you for reading today's newsletter! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/what-is-senior-software-engineer?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/what-is-senior-software-engineer?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/what-is-senior-software-engineer/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/p/what-is-senior-software-engineer/comments"><span>Leave a comment</span></a></p><p></p>]]></content:encoded></item><item><title><![CDATA[Redis Use Cases Examples in the Real-World]]></title><description><![CDATA[Redis is powerful tools that already used in wide range use cases such as: profile caching, session storage, redis for leaderboard, redis shopping cart, and more]]></description><link>https://www.coderbased.com/p/redis-use-cases-examples-in-the-real</link><guid isPermaLink="false">https://www.coderbased.com/p/redis-use-cases-examples-in-the-real</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Fri, 02 Jun 2023 08:01:24 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!vFKi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>Hello, I apologize for the delay in publishing. It was due to the extensive length of the content I wanted to write. Today, we will discuss the tools that have accelerated the growth of my career, technology that has greatly benefited me in my software engineering journey. It is Redis, we are going to learn redis real-world use cases including system design and pseudocode on how to implement it.</p><p>Follow me on <a href="https://twitter.com/herryg91">Twitter</a> &amp; <a href="https://www.linkedin.com/in/herryg91">Linkedin</a></p></blockquote><p>Quick Links:</p><ul><li><p><a href="https://www.thescalable.net/i/124759297/user-profile-cache-http-api-cache">User Profile Cache (HTTP API Cache)</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/redis-for-session-storage-login-and-logout">Session Storage</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/log-in-throttling">Log In Throttling</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/dynamic-pricing-in-hotel-industry-redis-distributed-locking">Dynamic Hotel Pricing Update (Redis Distributed Lock)</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/otp-one-time-password-using-redis">OTP (One Time Password) using Redis</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/waiting-list-in-help-desk-system-redis-for-job-queue">Waiting List in Help Desk System (Job Queue)</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/search-history-feature">Search History Feature</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/redis-for-shopping-cart-add-to-cart">Shopping Cart / Add to Cart</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/redis-real-time-analytics-view-like-transaction-etc">Real Time Analytics using Redis</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/redis-for-leaderboard">Leaderboard Service</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/redis-real-time-chat">Build Realtime Chat Using Redis (Direct Message &amp; Group Chat)</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/realtime-notification">Realtime Notification</a></p></li><li><p><a href="https://www.thescalable.net/i/124759297/geolocation-distance-driver-distance-and-attendance-system">Geolocation Distance (Find Driver Near Me &amp; Employee Check In)</a></p></li></ul><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:null}" data-component-name="ButtonCreateButton"><a class="button primary" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><div><hr></div><p>If you asked about the tools I love the most, Redis is definitely one of them. Redis is a great tool for two reasons:</p><ul><li><p>Simplicity: Redis is simple to understand and use.</p></li><li><p>Wide range of use cases: Redis can solve a lot of real-world use cases.</p></li></ul><p>Take a look the infographic what redis capable of in solving real-world use cases.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vFKi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vFKi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png 424w, https://substackcdn.com/image/fetch/$s_!vFKi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png 848w, https://substackcdn.com/image/fetch/$s_!vFKi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png 1272w, https://substackcdn.com/image/fetch/$s_!vFKi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vFKi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png" width="1456" height="835" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:835,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:293144,&quot;alt&quot;:&quot;Redis Use Cases Examples&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Redis Use Cases Examples" title="Redis Use Cases Examples" srcset="https://substackcdn.com/image/fetch/$s_!vFKi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png 424w, https://substackcdn.com/image/fetch/$s_!vFKi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png 848w, https://substackcdn.com/image/fetch/$s_!vFKi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png 1272w, https://substackcdn.com/image/fetch/$s_!vFKi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F43278dc1-3eb3-45ce-87f3-5f4a8f9e2735_2186x1254.png 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><blockquote><p>Notes: use cases above just a few cases that often we met in real life, but of course there are more use cases that can be solved by redis</p></blockquote><p>In almost every major tech industry, including e-commerce, ride-hailing, travel, and more, Redis can be utilized to solve various use cases. This truly showcases the power of Redis. Without further ado, let's go deeper into how Redis can be employed in real-world scenarios.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM"><div class="subscription-widget show-subscribe"><div class="preamble"><p class="cta-caption">The Scalable is a reader-supported publication. To receive new posts and support my work, consider becoming a free or paid subscriber.</p></div><form class="subscription-widget-subscribe"><input type="email" class="email-input" name="email" placeholder="Type your email&#8230;" tabindex="-1"><input type="submit" class="button primary" value="Subscribe"><div class="fake-input-wrapper"><div class="fake-input"></div><div class="fake-button"></div></div></form></div></div><h2>User Profile Cache (HTTP API Cache)</h2><p><code>Redis Commands: GET, SET, EXPIRE</code></p><p>HTTP API cache refers to the caching of HTTP responses from an API (Application Programming Interface). It involves storing the response of an API request in a cache, which can be subsequently used to serve future requests without the need to re-fetch the data from the API server.</p><p>One of the common use cases for API caching is storing user profiles. In an authentication system, usually only the user ID or email (something unique) is stored in the authentication token. However, the frontend often requires the user's name and profile picture on every page. Retrieving the user profile repeatedly can become redundant, so api caching with Redis can greatly enhance scalability.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!y_oS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4397f87a-1277-436c-8d74-b82aea354fff_976x672.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!y_oS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4397f87a-1277-436c-8d74-b82aea354fff_976x672.png 424w, https://substackcdn.com/image/fetch/$s_!y_oS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4397f87a-1277-436c-8d74-b82aea354fff_976x672.png 848w, https://substackcdn.com/image/fetch/$s_!y_oS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4397f87a-1277-436c-8d74-b82aea354fff_976x672.png 1272w, https://substackcdn.com/image/fetch/$s_!y_oS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4397f87a-1277-436c-8d74-b82aea354fff_976x672.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!y_oS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4397f87a-1277-436c-8d74-b82aea354fff_976x672.png" width="498" height="342.88524590163934" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4397f87a-1277-436c-8d74-b82aea354fff_976x672.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:672,&quot;width&quot;:976,&quot;resizeWidth&quot;:498,&quot;bytes&quot;:85975,&quot;alt&quot;:&quot;Api Caching with Redis System Design&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Api Caching with Redis System Design" title="Api Caching with Redis System Design" srcset="https://substackcdn.com/image/fetch/$s_!y_oS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4397f87a-1277-436c-8d74-b82aea354fff_976x672.png 424w, https://substackcdn.com/image/fetch/$s_!y_oS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4397f87a-1277-436c-8d74-b82aea354fff_976x672.png 848w, https://substackcdn.com/image/fetch/$s_!y_oS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4397f87a-1277-436c-8d74-b82aea354fff_976x672.png 1272w, https://substackcdn.com/image/fetch/$s_!y_oS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4397f87a-1277-436c-8d74-b82aea354fff_976x672.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><pre><code><strong>function</strong> GetUserProfile(user_id) {
    <strong>var</strong> cache_response = redis.<strong>Do</strong>(`GET user:{<em>user_id</em>}`)
    <strong>if</strong>(cache_response) {
        <strong>return</strong> json.<strong>Unmarshal</strong>(cache_response)
    }

    <strong>var</strong> response = <strong>getProfile</strong>(user_id)
    <strong>var</strong> marshalled_resp = json.<strong>Marshal</strong>(response)
    redis.<strong>Do</strong>(`SET user:{<em>user_id</em>} {<em>marshalled_resp</em>} EX 600`)
    <strong>return</strong> response
}</code></pre><p>HTTP REST APIs typically return JSON responses. If we want to utilize Redis to cache the responses, we can store <code>JSON string</code> as the cached value. For subsequent requests, we can simply unmarshalled the string and return the cached JSON object.</p><h2>Redis for Session Storage (Login &amp; Logout)</h2><p><code>Related Commands: GET, SET, EXPIRE, DEL</code></p><p>Session-based authentication is a widely used approach for user authentication in web applications. It involves generating a session token after login, which is then used to keep track of the authenticated user.</p><p>Similar to the issue with user profiles, the session token needs to be checked every time a user performs an action that requires authentication. Consequently, querying the database can easily become a bottleneck in high-traffic use cases. Therefore, using Redis for session storage is considered one of the best solutions.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HNCl!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d3e8f39-cca3-42dd-b8cc-d42d55f5d256_1008x1336.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HNCl!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d3e8f39-cca3-42dd-b8cc-d42d55f5d256_1008x1336.png 424w, https://substackcdn.com/image/fetch/$s_!HNCl!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d3e8f39-cca3-42dd-b8cc-d42d55f5d256_1008x1336.png 848w, https://substackcdn.com/image/fetch/$s_!HNCl!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d3e8f39-cca3-42dd-b8cc-d42d55f5d256_1008x1336.png 1272w, https://substackcdn.com/image/fetch/$s_!HNCl!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d3e8f39-cca3-42dd-b8cc-d42d55f5d256_1008x1336.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HNCl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d3e8f39-cca3-42dd-b8cc-d42d55f5d256_1008x1336.png" width="498" height="660.047619047619" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8d3e8f39-cca3-42dd-b8cc-d42d55f5d256_1008x1336.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1336,&quot;width&quot;:1008,&quot;resizeWidth&quot;:498,&quot;bytes&quot;:253441,&quot;alt&quot;:&quot;using redis to store session data&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="using redis to store session data" title="using redis to store session data" srcset="https://substackcdn.com/image/fetch/$s_!HNCl!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d3e8f39-cca3-42dd-b8cc-d42d55f5d256_1008x1336.png 424w, https://substackcdn.com/image/fetch/$s_!HNCl!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d3e8f39-cca3-42dd-b8cc-d42d55f5d256_1008x1336.png 848w, https://substackcdn.com/image/fetch/$s_!HNCl!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d3e8f39-cca3-42dd-b8cc-d42d55f5d256_1008x1336.png 1272w, https://substackcdn.com/image/fetch/$s_!HNCl!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8d3e8f39-cca3-42dd-b8cc-d42d55f5d256_1008x1336.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><pre><code><strong>function</strong> Login(email, password){
    <strong>var</strong> session_token = <strong>loginLogic</strong>()
    redis.<strong>Do</strong>(`SET user:session:{<em>session_token</em>} {<em>email</em>} EX 3600`)
    <strong>return</strong> session_token
}

<strong>function</strong> Logout(session_token){
    redis.<strong>Do</strong>(`DEL user:session:{<em>session_token</em>}`)
}

<strong>function</strong> VerifyToken(session_token) {
    <strong>var</strong> email = redis.<strong>Do</strong>(`GET user:session:{<em>session_token</em>}`)
    <strong>if</strong>(!email) {
        <strong>return</strong> null, <strong>errors</strong>(`token is expired or not exists`)
    }
    <strong>var</strong> user_detail = <strong>getUserDetail</strong>(email)
    <strong>return</strong> user_detail, null
}</code></pre><h2>Log In Throttling</h2><p><code>Related Command: INCRBY, EXPIRE, TTL</code></p><p>Authentication has many interesting use cases, one of which is preventing users from hacking other users through brute force attacks. One of the easiest ways to achieve this is by implementing throttling. Throttling refers to the practice of intentionally limiting the rate or speed of a process or service. You might have seen messages such:</p><blockquote><p><em>&#8220;There have been too many login failures. Try again in x seconds&#8221;</em></p></blockquote><p>This is an implementation of throttling for login attempts to prevent brute force attacks. In a simple manner, throttling involves storing the number of login attempts made by a user. However, storing this data in databases like MySQL or PostgreSQL may seem overly engineering. Additionally, databases like MySQL and PostgreSQL do not have built-in time-based expiration, unlike Redis. Using Redis to implement throttling is a straightforward solution. Please refer to the system design below:</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6afW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61bdd601-d1c8-4890-ab6f-b8ca82fdedca_1158x980.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6afW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61bdd601-d1c8-4890-ab6f-b8ca82fdedca_1158x980.png 424w, https://substackcdn.com/image/fetch/$s_!6afW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61bdd601-d1c8-4890-ab6f-b8ca82fdedca_1158x980.png 848w, https://substackcdn.com/image/fetch/$s_!6afW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61bdd601-d1c8-4890-ab6f-b8ca82fdedca_1158x980.png 1272w, https://substackcdn.com/image/fetch/$s_!6afW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61bdd601-d1c8-4890-ab6f-b8ca82fdedca_1158x980.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6afW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61bdd601-d1c8-4890-ab6f-b8ca82fdedca_1158x980.png" width="496" height="419.75820379965455" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/61bdd601-d1c8-4890-ab6f-b8ca82fdedca_1158x980.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:980,&quot;width&quot;:1158,&quot;resizeWidth&quot;:496,&quot;bytes&quot;:139011,&quot;alt&quot;:&quot;rate limiting using redis&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="rate limiting using redis" title="rate limiting using redis" srcset="https://substackcdn.com/image/fetch/$s_!6afW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61bdd601-d1c8-4890-ab6f-b8ca82fdedca_1158x980.png 424w, https://substackcdn.com/image/fetch/$s_!6afW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61bdd601-d1c8-4890-ab6f-b8ca82fdedca_1158x980.png 848w, https://substackcdn.com/image/fetch/$s_!6afW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61bdd601-d1c8-4890-ab6f-b8ca82fdedca_1158x980.png 1272w, https://substackcdn.com/image/fetch/$s_!6afW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F61bdd601-d1c8-4890-ab6f-b8ca82fdedca_1158x980.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><pre><code><strong>function</strong> Login(context, username, password){
    <strong>var</strong> guest_session = <strong>context</strong>.GuestSession
    <strong>var</strong> max_attempt = 5
    <strong>var</strong> current_attempt = redis.<strong>Do</strong>(`GET login_attempt:{<em>guest_session</em>}`)
    <strong>if</strong>(current_attempt &gt;= max_attempt){
        <strong>var</strong> expire_lock = redis.<strong>Do</strong>(`TTL login_attempt:{<em>guest_session</em>}`)
        <strong>return</strong> null, <strong>errors</strong>(`There have been too many login failures. Try again in {<em>expire_lock</em>} seconds`)
    }

    <strong>var</strong> is_login_success, auth_token = <strong>login</strong>(username, password)
    <strong>if</strong>(!is_login_success) {
        redis.<strong>Do</strong>(`INCR login_attempt:{<em>guest_session</em>}`)
        redis.<strong>Do</strong>(`EXPIRE login_attempt:{<em>guest_session</em>} 300`)
        <strong>return</strong> null, <strong>errors</strong>("user not found / invalid password")&#9;
    }
    redis.<strong>Do</strong>(`DEL login_attempt:{<em>guest_session</em>}`)
    <strong>return</strong> auth_token, null
} </code></pre><h2>Dynamic Pricing in Hotel Industry (Redis Distributed Locking)</h2><p><code>Related Command: GET, SET NX EX</code></p><p>When working with horizontal scaling or even microservices, it becomes necessary to implement distributed locking at the application level to address issues such as race conditions or thundering herd problems. Redis can be leveraged for distributed locking, offering several advantages including high scalability, fault tolerance, and strong consistency guarantees.</p><p>Consider a scenario where you are developing a hotel booking platform that fetches dynamic prices from a third-party API. In a situation where multiple users are requesting hotel information for the same date, you may want to avoid overwhelming the third-party API. Here, you can utilize Redis distributed locking to resolve this issue effectively.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!iHx6!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe697e1-262d-4de7-8d79-f3a0c61d303d_1158x708.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!iHx6!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe697e1-262d-4de7-8d79-f3a0c61d303d_1158x708.png 424w, https://substackcdn.com/image/fetch/$s_!iHx6!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe697e1-262d-4de7-8d79-f3a0c61d303d_1158x708.png 848w, https://substackcdn.com/image/fetch/$s_!iHx6!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe697e1-262d-4de7-8d79-f3a0c61d303d_1158x708.png 1272w, https://substackcdn.com/image/fetch/$s_!iHx6!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe697e1-262d-4de7-8d79-f3a0c61d303d_1158x708.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!iHx6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe697e1-262d-4de7-8d79-f3a0c61d303d_1158x708.png" width="494" height="302.03108808290153" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/dbe697e1-262d-4de7-8d79-f3a0c61d303d_1158x708.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:708,&quot;width&quot;:1158,&quot;resizeWidth&quot;:494,&quot;bytes&quot;:130938,&quot;alt&quot;:&quot;dynamic pricing in hotel industry system design&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="dynamic pricing in hotel industry system design" title="dynamic pricing in hotel industry system design" srcset="https://substackcdn.com/image/fetch/$s_!iHx6!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe697e1-262d-4de7-8d79-f3a0c61d303d_1158x708.png 424w, https://substackcdn.com/image/fetch/$s_!iHx6!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe697e1-262d-4de7-8d79-f3a0c61d303d_1158x708.png 848w, https://substackcdn.com/image/fetch/$s_!iHx6!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe697e1-262d-4de7-8d79-f3a0c61d303d_1158x708.png 1272w, https://substackcdn.com/image/fetch/$s_!iHx6!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fdbe697e1-262d-4de7-8d79-f3a0c61d303d_1158x708.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><pre><code><strong>function</strong> CheckHotelPrice(hotel_id, book_date) {
    <strong>var</strong> price_detail = null
    <strong>while</strong>(true) {
        price_detail = redis.<strong>Do</strong>(`GET hotel_price:{<em>hotel_id</em>}:{<em>book_date</em>}`)
        <strong>if</strong>(price_detail != null){
            <strong>break</strong>
        }
&#9;&#9;
        <strong>var</strong> current_machine_name = os.<strong>GetHostname</strong>()
        <strong>var</strong> acquire_lock = redis.<strong>Do</strong>(`SET hotel_price:{<em>hotel_id</em>}:{<em>book_date</em>}:lock {<em>current_machine_name</em>} <strong>NX</strong> <strong>EX</strong> 5`)
        
        <strong>if</strong>(!acquire_lock){
            <strong>sleep</strong>(250) // waiting 250 ms
            <strong>continue</strong>
        }
&#9;&#9;
        price_detail = <strong>getHotelPriceFromThirdParty</strong>(hotel_id, booking_at)
        redis.<strong>Do</strong>(`SET hotel_price:{<em>hotel_id</em>}:{<em>book_date</em>} {<em>price_detail</em>} EX 600`)
&#9;<strong>break</strong>
    }

    <strong>return</strong> price_detail
}</code></pre><h2>OTP (One Time Password) using Redis</h2><p><code>Related Command: SET NX EX, GET, DEL</code></p><p>"OTP" stands for "One-Time Password." It is a security measure used to authenticate users and verify their identity during online transactions or account logins. A one-time password is a unique and temporary code that is typically valid for a short period of time, usually for a single login session or transaction. Since Redis has time-based expiration using the <code>EXPIRE</code> command, it is well-suited for building an OTP (One-Time Password) system.</p><p>The OTP system consists of two functions:</p><ul><li><p>Generate OTP</p></li><li><p>Verify OTP</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8BKo!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F427008f8-149e-4171-a04d-e58797d0fb90_1154x1032.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8BKo!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F427008f8-149e-4171-a04d-e58797d0fb90_1154x1032.png 424w, https://substackcdn.com/image/fetch/$s_!8BKo!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F427008f8-149e-4171-a04d-e58797d0fb90_1154x1032.png 848w, https://substackcdn.com/image/fetch/$s_!8BKo!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F427008f8-149e-4171-a04d-e58797d0fb90_1154x1032.png 1272w, https://substackcdn.com/image/fetch/$s_!8BKo!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F427008f8-149e-4171-a04d-e58797d0fb90_1154x1032.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8BKo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F427008f8-149e-4171-a04d-e58797d0fb90_1154x1032.png" width="498" height="445.35181975736566" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/427008f8-149e-4171-a04d-e58797d0fb90_1154x1032.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1032,&quot;width&quot;:1154,&quot;resizeWidth&quot;:498,&quot;bytes&quot;:147200,&quot;alt&quot;:&quot;OTP System Design using redis&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="OTP System Design using redis" title="OTP System Design using redis" srcset="https://substackcdn.com/image/fetch/$s_!8BKo!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F427008f8-149e-4171-a04d-e58797d0fb90_1154x1032.png 424w, https://substackcdn.com/image/fetch/$s_!8BKo!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F427008f8-149e-4171-a04d-e58797d0fb90_1154x1032.png 848w, https://substackcdn.com/image/fetch/$s_!8BKo!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F427008f8-149e-4171-a04d-e58797d0fb90_1154x1032.png 1272w, https://substackcdn.com/image/fetch/$s_!8BKo!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F427008f8-149e-4171-a04d-e58797d0fb90_1154x1032.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Redis can be leveraged to build an OTP system. Below is pseudocode that demonstrates how Redis can be used to develop an OTP system:</p><pre><code><strong>function</strong> GenerateOTP(phone_number) {
    <strong>var</strong> otp_code = <strong>generate_otp_code</strong>(6)
    <strong>var</strong> is_success = redis.<strong>Do</strong>(`SET otp:{<em>phone_number</em>} otp_code NX<strong> </strong>EX 600`)
    <strong>if</strong>(!is_success){
        <strong>var</strong> ttl = redis.<strong>Do</strong>(`TTL otp:{<em>phone_number</em>}`)
        <strong>return</strong> <strong>errors</strong>("otp has been sent, try again in {<em>ttl</em>} minutes")
    }
    <strong>sendOtpViaSMS</strong>(phone_number, otp_code)
    <strong>return</strong> null
}

<strong>function</strong> VerifyOTP(phone_number, otp_code) {
    <strong>var</strong> stored_otp = redis.<strong>Do</strong>(`GET otp:{<em>phone_number</em>}`)
    <strong>if</strong>(!stored_otp){
        <strong>return</strong> errors(`Code has been expired`)
    } <strong>else</strong> <strong>if</strong>(stored_otp != otp_code){
        <strong>return</strong> <strong>errors</strong>(`Invalid OTP Code`)
    }
&#9;
    redis.<strong>Do</strong>(`DEL otp:{<em>phone_number</em>}`)
    <strong>return</strong> null
}</code></pre><h2>Waiting List in Help Desk System (Redis for Job Queue)</h2><p><code>Related Commands: LPUSH, RPOPLPUSH, LREM, LPOS</code></p><p>A help desk is a system designed to manage and streamline customer support and issue resolution processes within an organization. When the number of support request much bigger than the number of customer support it will generate a problem.</p><blockquote><p>Imagine you only have 3 customer support officer and at one time there are 100 request to have chat support, how to solve it?</p></blockquote><p>It&#8217;s a common where help desk system has waiting list mechanism. In technical, waiting list is similar to <code>JOB QUEUE</code> in data structure. Redis has a powerfull command to solve job queue problems. In a help desk system, there are at least two functions:</p><ul><li><p>Create Request (by User)</p></li><li><p>Handle Support Request (by Customer Support)</p></li></ul><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8nCZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a5f6a36-497e-4389-8e95-066e42f2c2f5_1082x1098.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8nCZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a5f6a36-497e-4389-8e95-066e42f2c2f5_1082x1098.png 424w, https://substackcdn.com/image/fetch/$s_!8nCZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a5f6a36-497e-4389-8e95-066e42f2c2f5_1082x1098.png 848w, https://substackcdn.com/image/fetch/$s_!8nCZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a5f6a36-497e-4389-8e95-066e42f2c2f5_1082x1098.png 1272w, https://substackcdn.com/image/fetch/$s_!8nCZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a5f6a36-497e-4389-8e95-066e42f2c2f5_1082x1098.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8nCZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a5f6a36-497e-4389-8e95-066e42f2c2f5_1082x1098.png" width="498" height="505.3641404805915" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0a5f6a36-497e-4389-8e95-066e42f2c2f5_1082x1098.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1098,&quot;width&quot;:1082,&quot;resizeWidth&quot;:498,&quot;bytes&quot;:207243,&quot;alt&quot;:&quot;Redis for Job Queue in Waiting List System&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Redis for Job Queue in Waiting List System" title="Redis for Job Queue in Waiting List System" srcset="https://substackcdn.com/image/fetch/$s_!8nCZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a5f6a36-497e-4389-8e95-066e42f2c2f5_1082x1098.png 424w, https://substackcdn.com/image/fetch/$s_!8nCZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a5f6a36-497e-4389-8e95-066e42f2c2f5_1082x1098.png 848w, https://substackcdn.com/image/fetch/$s_!8nCZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a5f6a36-497e-4389-8e95-066e42f2c2f5_1082x1098.png 1272w, https://substackcdn.com/image/fetch/$s_!8nCZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0a5f6a36-497e-4389-8e95-066e42f2c2f5_1082x1098.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><pre><code><strong>function</strong> CreateRequest(payload){
    <strong>var</strong> request_id = <strong>createSupportRequest</strong>(payload)
    redis.<strong>Do</strong>(`LPUSH helpdesk {<em>request_id</em>}`)
}

<strong>function</strong> GetQueuePos(request_id){
    <strong>var</strong> my_queue_number = redis.<strong>Do</strong>(`LPOS<strong> </strong>helpdesk {<em>request_id</em>} RANK -1`)
    // Notes: "RANK -1" means you reverse the sort
    <strong>return</strong> my_queue_number + 1
}

<strong>function</strong> HandleSupportRequest(cs_id){
    <strong>while</strong> (true) {
        <strong>var</strong> request_id = redis.Do(`RPOPLPUSH helpdesk helpdesk:{<em>cs_id</em>}`)
        <strong>if</strong>(request_id == null) {
            <strong>sleep</strong>(60)
            <strong>continue</strong>
        }
        <strong>var</strong> request_detail = <strong>getSupportRequest</strong>(request_id)
        <strong>connect</strong>(cs_id, request_detail.user_id)
        redis.<strong>Do</strong>(`LREM<strong> </strong>helpdesk:{<em>customer_support_id</em>} 1 {<em>request_id</em>}`
    }
}</code></pre><h2>Search History Feature</h2><p><code>Related Commands: LPUSH, LRANGE, LREM</code></p><p>Search history is a common feature that we often met in various website including e-commerce, news, etc. Everytime user searching some keywords, the keyword would be stored and will be pop up in the next searching.</p><p>Search history is basically a data structure problem, and with redis we can use list commands to build this feature.</p><pre><code><strong>function</strong> Search(user_id, keywords) {
    <strong>var</strong> resp = <strong>searchLogic</strong>(keywords)
    redis.<strong>Do</strong>(`LREM history:{<em>user_id</em>} 1 {<em>keywords</em>}`)
    redis.<strong>Do</strong>(`LPUSH history:{<em>user_id</em>} {<em>keywords</em>}`)
    <strong>return</strong> resp
}

<strong>function</strong> GetSearchHistory(user_id) {
    <strong>var</strong> histories = redis.<strong>Do</strong>(`LRANGE history:{<em>user_id</em>} 0 -1`)
    <strong>return</strong> histories
}</code></pre><h2>Redis for Shopping Cart (Add to Cart)</h2><p><code>Related Commands: HGETALL, HINCRBY, HDEL</code></p><p><em>Shopping Cart / Add to Cart</em> feature is commonly found on e-commerce websites or online shopping platforms. It allows users to select products they wish to purchase by clicking on the "Add to cart" button or a similar option. This action adds the chosen item to a virtual shopping cart, serving as a temporary storage before finalizing the transaction.</p><p>Once items are added to the cart, users can typically view the contents, make changes to quantities or options, and remove items if necessary. To implement the "Add to Cart" feature, a storage system is required, and Redis can be leveraged for this purpose.</p><p>See the pseudocode below on how redis can be used for add to cart feature:</p><pre><code><strong>function</strong> CreateAddToCart(user_id, item_id){
    redis.<strong>Do</strong>(`HINCRBY cart:{<em>user_id</em>} {<em>item_id</em>} 1`)
}

<strong>function</strong> ChangeQuantity(user_id, item_id, quantity){
    <strong>var</strong> current_qty = redis.<strong>Do</strong>(`HSET cart:{<em>user_id</em>} {<em>item_id</em>} {<em>quantity</em>}`)

    <strong>if</strong>(current_qty &lt;= 0){
        <strong>RemoveAddToCart</strong>(user_id, item_id)
    }
}

<strong>function</strong> GetAllAddToCart(user_id){
    <strong>var</strong> shopping_carts = redis.<strong>Do</strong>(`HGETALL cart:{<em>user_id</em>}`)
    <strong>return</strong> shopping_carts
}

<strong>function</strong> RemoveAddToCart(user_id, item_id){
    redis.<strong>Do</strong>(`HDEL cart:{<em>user_id</em>} {<em>item_id</em>}`) 
}</code></pre><h2>Redis Real Time Analytics (View, Like, Transaction, etc.)</h2><p><code>Related Commands: HGETALL, HINCRBY</code></p><p>Redis hash commands (with the prefix H) are commonly used by tech companies to track real-time analytics such as views, likes, transactions, and more. Implementing this functionality is straightforward and efficient using the <code>HINCRBY</code> command to increment the count of the data we want to track. To retrieve and display the tracked data, we can use the <code>HGETALL</code> or <code>HGET</code> command.</p><p>To gain a better understanding, let's imagine that we are an e-commerce company aiming to track real-time data on product page views, wishlists, and transactions. See the pseudocode below</p><pre><code><strong>function</strong> ViewProduct(product_id) {
    <strong>var</strong> product_info = <strong>getProduct</strong>(product_id)
    redis.<strong>Do</strong>(`HCINRBY product:tracker:{<em>product_id</em>} view 1`)
}

<strong>function</strong> Wishlist(user_id, product_id) {
    <strong>wishlistLogic</strong>(user_id, product_id)
    redis.<strong>Do</strong>(`HCINRBY product:tracker:{<em>product_id</em>} wishlist 1`)
}

<strong>function</strong> CreateTransaction(user_id, product_id) {
    <strong>createTransactionLogic</strong>(user_id, product_id)
    redis.<strong>Do</strong>(`HCINRBY product:tracker:{<em>product_id</em>} transaction 1`)
}

<strong>function</strong> GetProductStatistic(product_id) {
    <strong>var</strong> stats = redis.<strong>Do</strong>(`HGETALL product:tracker:{<em>product_id</em>} `)
    <strong>return</strong> stats
}</code></pre><h2>Redis for Leaderboard</h2><p><code>Related Commands: ZADD, ZRANGE</code></p><p>Leaderboards are commonly utilized in gamification or competitive environments. They consist of several components, including:</p><ul><li><p>Users</p></li><li><p>Score</p></li><li><p>Rank</p></li></ul><p>Redis sorted sets are an excellent choice for storing user data and their corresponding scores, which can then be sorted to determine ranks. Redis's exceptional speed makes it suitable for leaderboard use cases that require frequent read and write operations.</p><p>We have previously discussed the Leaderboard System Design. For more information, please refer to the article we discussed earlier.</p><div class="digest-post-embed" data-attrs="{&quot;nodeId&quot;:&quot;be267e42-d2c3-483a-9837-6728e80d2f9f&quot;,&quot;caption&quot;:&quot;Build leaderboard database &amp;amp; system design including redis leaderboard system&quot;,&quot;cta&quot;:null,&quot;showBylines&quot;:true,&quot;size&quot;:&quot;md&quot;,&quot;isEditorNode&quot;:true,&quot;title&quot;:&quot;Leaderboard System Design&quot;,&quot;publishedBylines&quot;:[{&quot;id&quot;:140347336,&quot;name&quot;:&quot;Herry Gunawan&quot;,&quot;bio&quot;:&quot;Writing Hands-on DB | CTO &amp; Co-Founder Gajiku\n\nI have a lot of experience in building scalable systems and products. One example is when I successfully managed a 500x increase in traffic during the biggest event in my country.\n&quot;,&quot;photo_url&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/85021d27-1a23-4cba-9a97-4318cfb7cc18_512x512.jpeg&quot;,&quot;is_guest&quot;:false,&quot;bestseller_tier&quot;:null}],&quot;post_date&quot;:&quot;2023-05-18T04:59:27.003Z&quot;,&quot;cover_image&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fef39e54-2df0-4111-81aa-8c3e313b98a5_1456x724.png&quot;,&quot;cover_image_alt&quot;:null,&quot;canonical_url&quot;:&quot;https://www.thescalable.net/p/dot6-leaderboard-system-design&quot;,&quot;section_name&quot;:null,&quot;video_upload_id&quot;:null,&quot;id&quot;:122159756,&quot;type&quot;:&quot;newsletter&quot;,&quot;reaction_count&quot;:1,&quot;comment_count&quot;:0,&quot;publication_id&quot;:null,&quot;publication_name&quot;:&quot;The Scalable&quot;,&quot;publication_logo_url&quot;:&quot;https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F91bbb456-151d-43a1-9ffc-2f694121655c_500x500.png&quot;,&quot;belowTheFold&quot;:true,&quot;youtube_url&quot;:null,&quot;show_links&quot;:null,&quot;feed_url&quot;:null}"></div><p>But, Here is a sneak peek at how Redis can be used for implementing a leaderboard feature. Please find the pseudocode below:</p><pre><code><strong>function</strong> AddScore(user_id, score){
    redis.<strong>Do</strong>(`ZADD leaderboard {<em>score</em>} {<em>user_id</em>}`)
}

<strong>function</strong> GetTop10(){
    <strong>var</strong> top_ten_leaderboard = redis.<strong>Do</strong>(`ZRANGE leaderboard 0 9`)
    <strong>var</strong> resp = <strong>getLeaderboardDetails</strong>(top_ten_leaderboard)
    <strong>return</strong> resp
}</code></pre><h2>Redis Real Time Chat</h2><p><code>Related Commands: PUBLISH, SUBSCRIBE</code></p><p>When discussing chat application, we often refer to <em>WebSocket</em> systems or protocols like <em>XMPP</em> (WhatsApp have using this in its early day). However, these solutions primarily address real-time communication challenges between the frontend and backend. While they may be suitable for single-machine systems, scaling the system horizontally can become problematic. Fortunately, Redis offers a powerful solution called PUBSUB (publish-subscribe). This mechanism allows us to leverage PUBSUB for building a chat system. Let's explore two use cases:</p><ol><li><p>Direct Chat 1:1 Chat</p></li><li><p>Group Chat</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!toLY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F082793b7-c35f-4dde-b130-d022041db13d_1252x1216.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!toLY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F082793b7-c35f-4dde-b130-d022041db13d_1252x1216.png 424w, https://substackcdn.com/image/fetch/$s_!toLY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F082793b7-c35f-4dde-b130-d022041db13d_1252x1216.png 848w, https://substackcdn.com/image/fetch/$s_!toLY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F082793b7-c35f-4dde-b130-d022041db13d_1252x1216.png 1272w, https://substackcdn.com/image/fetch/$s_!toLY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F082793b7-c35f-4dde-b130-d022041db13d_1252x1216.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!toLY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F082793b7-c35f-4dde-b130-d022041db13d_1252x1216.png" width="502" height="487.5654952076677" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/082793b7-c35f-4dde-b130-d022041db13d_1252x1216.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1216,&quot;width&quot;:1252,&quot;resizeWidth&quot;:502,&quot;bytes&quot;:305140,&quot;alt&quot;:&quot;Redis Real Time Chat for Chat Application&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="Redis Real Time Chat for Chat Application" title="Redis Real Time Chat for Chat Application" srcset="https://substackcdn.com/image/fetch/$s_!toLY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F082793b7-c35f-4dde-b130-d022041db13d_1252x1216.png 424w, https://substackcdn.com/image/fetch/$s_!toLY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F082793b7-c35f-4dde-b130-d022041db13d_1252x1216.png 848w, https://substackcdn.com/image/fetch/$s_!toLY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F082793b7-c35f-4dde-b130-d022041db13d_1252x1216.png 1272w, https://substackcdn.com/image/fetch/$s_!toLY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F082793b7-c35f-4dde-b130-d022041db13d_1252x1216.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Let's begin with the pseudocode for the 1:1 (direct message) chat feature.</p><p>Note: The key aspect of the 1:1 chat (direct message)  feature is that the Redis key needs to be consistent, regardless of whether you are <code>user_a</code> or <code>user_b</code>. Both users should have the same Redis key string.</p><pre><code><strong>function</strong> generateRedisKey(){
    <strong>var</strong> user_a = your_user_id
    <strong>var</strong> user_b = target_user_id
    <strong>if</strong>(user_a &gt; user_b){
        user_a = target_user_id
        user_b = your_user_id
    }
    <strong>return</strong> `directchat:{<em>user_a</em>}:{<em>user_b</em>}`
}

<strong>function</strong> JoinChat(your_user_id, target_user_id){
    <strong>var</strong> redis_key = <strong>generateRedisKey</strong>(your_user_id, target_user_id)
    <strong>var</strong> subscribe_handle = redis.<strong>Do</strong>(`SUBSCRIBE {<em>redis_key</em>}`)
    subscribe_handle.<strong>OnMessage</strong>((message) {
        if(message == "\quit") {
            <strong>return</strong>
        }
        // do something with message
    })
}

<strong>function</strong> SendMessage(your_user_id, target_user_id, message){
    <strong>var</strong> redis_key = <strong>generateRedisKey</strong>(your_user_id, target_user_id)
    redis.<strong>Do</strong>(`PUBLISH {<em>redis_key</em>} {<em>message</em>}`)
}

<strong>function</strong> CloseChat(your_user_id, target_user_id){
    <strong>var</strong> redis_key = <strong>generateRedisKey</strong>(your_user_id, target_user_id)
    redis.<strong>Do</strong>(`PUBLISH {redis_key} "\quit"`)
}</code></pre><p>If you want to implement a group chat feature, the approach is quite similar, with the key difference lying in the structuring of the Redis keys. Let's take a look at the following pseudocode to understand it better</p><pre><code><strong>function</strong> JoinChat(user_id, group_id){
    <strong>var</strong> subscribe_handle = redis.<strong>Do</strong>(`SUBSCRIBE chat:group:{group_id}`)
    subscribe_handle.<strong>OnMessage</strong>((message) {
        if(message == "\quit") {
            <strong>return</strong>
        }
        // do something with message
    })
}

<strong>function</strong> SendMessage(user_id, group_id, message){
    redis.<strong>Do</strong>(`PUBLISH chat:group:{<em>group_id</em>} {<em>message</em>}`)
}

<strong>function</strong> CloseChat(user_id, group_id){
    redis.<strong>Do</strong>(`PUBLISH chat:group:{<em>group_id</em>} "\quit"`)
}</code></pre><p>The chat system we've discussed so far is a simple implementation. Real-world chat systems like Twitch chat, Slack, and Discord have more complex features and requirements. However, I believe Redis can still be leveraged to build even these more complex chat systems. (Maybe later I will write special related to building chat application). </p><h2>Realtime Notification</h2><p><code>Related Commands: PUBLISH, SUBSCRIBE</code></p><p>Real-time notification is a useful feature that is typically used to engage your customers, such as providing announcements, promotions, and more. Marketers often utilize this feature to communicate their marketing strategies. </p><p>It is similar to how Redis can be used to build real-time chat features. By utilizing WebSockets and Redis, we can create real-time notifications. In the Redis component, we can employ PUBSUB commands to facilitate real-time notifications</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!7Uyk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd940f0af-46f4-4b0e-93d2-108585ef2d50_1474x898.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!7Uyk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd940f0af-46f4-4b0e-93d2-108585ef2d50_1474x898.png 424w, https://substackcdn.com/image/fetch/$s_!7Uyk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd940f0af-46f4-4b0e-93d2-108585ef2d50_1474x898.png 848w, https://substackcdn.com/image/fetch/$s_!7Uyk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd940f0af-46f4-4b0e-93d2-108585ef2d50_1474x898.png 1272w, https://substackcdn.com/image/fetch/$s_!7Uyk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd940f0af-46f4-4b0e-93d2-108585ef2d50_1474x898.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!7Uyk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd940f0af-46f4-4b0e-93d2-108585ef2d50_1474x898.png" width="500" height="304.60164835164835" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d940f0af-46f4-4b0e-93d2-108585ef2d50_1474x898.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:887,&quot;width&quot;:1456,&quot;resizeWidth&quot;:500,&quot;bytes&quot;:255371,&quot;alt&quot;:&quot;redis for real-time notification system design&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="redis for real-time notification system design" title="redis for real-time notification system design" srcset="https://substackcdn.com/image/fetch/$s_!7Uyk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd940f0af-46f4-4b0e-93d2-108585ef2d50_1474x898.png 424w, https://substackcdn.com/image/fetch/$s_!7Uyk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd940f0af-46f4-4b0e-93d2-108585ef2d50_1474x898.png 848w, https://substackcdn.com/image/fetch/$s_!7Uyk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd940f0af-46f4-4b0e-93d2-108585ef2d50_1474x898.png 1272w, https://substackcdn.com/image/fetch/$s_!7Uyk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd940f0af-46f4-4b0e-93d2-108585ef2d50_1474x898.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><pre><code><strong>function</strong> WebsocketConnect(ws_context, user_id){
    <strong>var</strong> subscribe_handle = redis.<strong>Do</strong>(`SUBSCRIBE notification:{<em>user_id</em>}`)
    subscribe_handle.<strong>OnMessage</strong>((message) {
        ws_context.Push(message)
    })
}

<strong>function</strong> Broadcast(user_id, message){
    redis.<strong>Do</strong>(`PUBLISH notification:{<em>user_id</em>} {<em>message</em>}`)
}
</code></pre><h2>Geolocation Distance: Driver Distance &amp; Attendance System</h2><p><code>Related Commands: GEOADD, GEODIST, GEOSEARCH</code></p><p>Redis has another feature related to geolocation. This geolocation functionality is typically used in various scenarios. Here are some scenarios that you might related to:</p><ol><li><p>Ride Hailing. You might need to find which driver that near the user and how is the distance</p></li><li><p>Employee Attendance System. In attendance system, checkin via mobile apps might requires geolocation checking to ensure the employee really come to the location.</p></li><li><p>Maps. I think we don;t need to explain what relation geolocation and map</p></li></ol><p>Now we are going to focus on ride hailing and attendance system. In redis geolocation funciton can be implemented using commands with prefix <code>GEO.</code> Let&#8217;s start with solving ride hailing problem, which is retrieve all driver that near to the customer. </p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!FoFR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d084b23-4118-4c19-8a05-7ce009164d04_1422x932.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!FoFR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d084b23-4118-4c19-8a05-7ce009164d04_1422x932.png 424w, https://substackcdn.com/image/fetch/$s_!FoFR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d084b23-4118-4c19-8a05-7ce009164d04_1422x932.png 848w, https://substackcdn.com/image/fetch/$s_!FoFR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d084b23-4118-4c19-8a05-7ce009164d04_1422x932.png 1272w, https://substackcdn.com/image/fetch/$s_!FoFR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d084b23-4118-4c19-8a05-7ce009164d04_1422x932.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!FoFR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d084b23-4118-4c19-8a05-7ce009164d04_1422x932.png" width="508" height="332.9507735583685" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2d084b23-4118-4c19-8a05-7ce009164d04_1422x932.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:932,&quot;width&quot;:1422,&quot;resizeWidth&quot;:508,&quot;bytes&quot;:214580,&quot;alt&quot;:&quot;redis geo query ride hailing system design&quot;,&quot;title&quot;:null,&quot;type&quot;:&quot;image/png&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="redis geo query ride hailing system design" title="redis geo query ride hailing system design" srcset="https://substackcdn.com/image/fetch/$s_!FoFR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d084b23-4118-4c19-8a05-7ce009164d04_1422x932.png 424w, https://substackcdn.com/image/fetch/$s_!FoFR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d084b23-4118-4c19-8a05-7ce009164d04_1422x932.png 848w, https://substackcdn.com/image/fetch/$s_!FoFR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d084b23-4118-4c19-8a05-7ce009164d04_1422x932.png 1272w, https://substackcdn.com/image/fetch/$s_!FoFR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d084b23-4118-4c19-8a05-7ce009164d04_1422x932.png 1456w" sizes="100vw" loading="lazy"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><pre><code><strong>function</strong> DriverUpdateLocation(driver_id, lat, lng){
    redis.<strong>Do</strong>(`GEOADD ridehailing {<em>lng</em>} {<em>lat</em>} {<em>driver_id</em>}`)
}

<strong>function</strong> FindDriverNearMe(lat, lng){
    <strong>var</strong> driver_with_distance = redis.<strong>Do</strong>(`GEOSEARCH ridehailing {<em>lng</em>} {<em>lat</em>} BY BOX 100 100 KM ASC WITHDIST`)
    
    <strong>var</strong> resp = <strong>getDriverDetail</strong>(driver_with_distance)

    <strong>return</strong> resp
}</code></pre><p>If you understand how ride-hailing services can utilize Redis geolocation to solve their problems, then understanding the usage in an attendance system becomes easy. The concept is similar, but the key difference lies in the location being searched. In ride-hailing, the location pertains to the driver, which is dynamically updated. However, in an attendance system, the location refers to the fixed company location. As a result, it needs to be pre-filled into Redis.</p><pre><code><strong>function</strong> PrefillCompanyLocation(){
    redis.<strong>Do</strong>(`GEOADD company_location {<em>lng_1</em>} {<em>lat_1</em>} {<em>location_id_1</em>}`)
    redis.<strong>Do</strong>(`GEOADD company_location {<em>lng_2</em>} {<em>lat_2</em>} {<em>location_id_2</em>}`)
    redis.<strong>Do</strong>(`GEOADD company_location {<em>lng_3</em>} {<em>lat_3</em>} {<em>location_id_3</em>}`)
}

<strong>function</strong> CheckIn(employee_id, location_id, lat, lng){
    <strong>var</strong> company_locations = redis.<strong>Do</strong>(`GEOSEARCH company_location {<em>lng</em>} {<em>lat</em>} BYRADIUS 10 M ASC`)
    
    <strong>if</strong>(company_locations[location_id] == null){
       <strong>return</strong> <strong>errors</strong>(`You are not in location range`) 
    }
    
    <strong>checkinLogic</strong>(employee_id, location_id, <strong>NOW</strong>())
    <strong>return</strong> null
}</code></pre><div><hr></div><p>That's all for today. It was quite a long list, but it truly highlighted the power of Redis. I suggest you learn the fundamentals of Redis and how to utilize it to solve problems in your professional life. However, keep in mind that while Redis is powerful, there may be cases where it's better to use another technology. Stay open-minded, don&#8217;t become fanatics to one technology and, in the end, remember &#8220;always get back to the fundamentals&#8221;.</p><div><hr></div><p>Thank you for reading today's newsletter! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/redis-use-cases-examples-in-the-real?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.coderbased.com/p/redis-use-cases-examples-in-the-real?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/redis-use-cases-examples-in-the-real/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.coderbased.com/p/redis-use-cases-examples-in-the-real/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item><item><title><![CDATA[Annoying rockstar, Useless EM and Don't want to Grow]]></title><description><![CDATA[How to handle rockstar software engineer that makes other not efficient, handling non-technical engineer manager and peers or mentee that don't want to grow.]]></description><link>https://www.coderbased.com/p/til2-annoying-rockstar-useless-em</link><guid isPermaLink="false">https://www.coderbased.com/p/til2-annoying-rockstar-useless-em</guid><dc:creator><![CDATA[Herry Gunawan]]></dc:creator><pubDate>Tue, 30 May 2023 08:00:56 GMT</pubDate><enclosure url="https://substack-post-media.s3.amazonaws.com/public/images/7a09b2f5-f96f-425e-9922-8848d78a7579_1244x602.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote><p>We will have 3 real-world questions about Software Engineers topics such as: system design, softskill, leadership, career advice and more&#8230;</p><p>To receive full access and support The Scalable, consider to subscribe us if you haven&#8217;t already!</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p></blockquote><p><strong>Quick Link:</strong></p><ul><li><p><a href="https://www.thescalable.net/i/124251501/annoying-rockstar-software-engineer">Annoying Rockstar Software Engineer</a></p></li><li><p><a href="https://www.thescalable.net/i/124251501/useless-engineer-manager">Useless Engineer Manager</a></p></li><li><p><a href="https://www.thescalable.net/i/124251501/doesnt-want-to-grow">Doesn&#8217;t Want to Grow</a></p></li></ul><div><hr></div><h2>Annoying Rockstar Software Engineer</h2><h5>Question</h5><blockquote><p>Hi, I recently joined a company as a Senior Software Engineer. There is an Individual Contributor who has been with the company for quite some time. I categorized him as a rockstar since he has been capable of handling complex tasks in the past (based on feedback from our managers and head).</p><p>Initially, I didn't mind this Rockstar Guy until I realized that he constantly changes his approach to development. My codebase is always getting changed into a new style, which forces me to learn from scratch each time I want to improve the product. Additionally, he is uncommunicative, and I don't think I can resolve this issue by talking to my manager and head. What should I do?</p></blockquote><h5>Answer</h5><p>From my perspective, it seems that your company lacks code standardization and a procedure for changing the standards. In larger companies, code standardization is crucial and not easy to change. Typically, there is a procedure, often referred to as an RFC (Request for Change), that needs to be reviewed and agreed upon by relevant stakeholders. Furthermore, there should be a rollout strategy in place.</p><p>If I were in your position, I would propose implementing code standardization and an RFC. However, I understand that you might not have the authority to make such decisions. That's why I believe it's still important to communicate with your manager and head. If you are hesitant to initiate communication with higher-ups, I don't think your problem can be resolved. Ultimately, you need authoritative individuals who can make decisions to address this kind of issue.</p><p>To approach the conversation, consider the following strategy:</p><ol><li><p><strong>Point out the problem</strong>: Highlight the need to start from scratch and the lack of communication as legitimate concerns to begin the discussion.</p></li><li><p><strong>Focus on the impact in global</strong>: Emphasize the impact on the team or delivery rate, rather than simply expressing personal preferences.</p></li><li><p><strong>Provide a solution</strong>: Explain how implementing code standardization and an RFC can address the issues. Elaborate on the benefits and potential positive outcomes.</p></li></ol><p>In this case don&#8217;t forget to <strong>seek support from peers</strong>. Gather testimonials from other colleagues who may have also experienced these problems. Show that this is a shared concern among the team and that unity is necessary to address it.</p><h2>Useless Engineer Manager</h2><h5>Question</h5><blockquote><p>Hi, I work at a small tech company and I'm currently part of a product development team, reporting to the engineering manager. Unfortunately, it seems that this EM doesn't seems understand any technical. I don't understand how this guy is able to advance his career to this level.</p><p>The most frustrating aspect is that he consistently agrees to requests from the business teams without fully comprehending the technical implications. As a result, I often have to work overtime to compensate for the poor decisions he makes. What should I do in this situation?</p></blockquote><h5>Answer</h5><p>I have identified two problems in your story:</p><ol><li><p>You are working overtime due to the engineering manager's reckless decisions.</p></li><li><p>You lack respect for the engineering manager because of his lack of technical knowledge.</p></li></ol><p>Before I share my idea, let me ask you a question: </p><p><em>&#8220;Are you okay with his lack of technical knowledge if he doesn't burden you?&#8221;</em></p><p>If your answer is yes, then you need to have a conversation with the engineering manager. </p><ul><li><p>You need to let your manager <strong>know you expectation</strong>. It is clearly okay to set expectation to superior</p></li><li><p>Let him know the situation and what really happen. If you have retrospective session then it is a good  </p></li></ul><p>Consider the following strategy for addressing the issue:</p><ol><li><p><strong>List down the specific incidents:</strong> Clearly point out instances where he made decisions without consulting the team.</p></li><li><p><strong>Explain the impact on the team and the company:</strong> Highlight the inefficiency in delivery quality and the potential for burnout.</p></li><li><p><strong>Propose a solution</strong>: Suggest establishing a clear scope of work and recommend that he consult with you for every decision. Ensure that all stakeholders, including other divisions such as the business team, understand that the engineering manager should not make any decision without involving the team.</p></li></ol><p>However, if you have a problem with his lack of technical knowledge, it may be necessary to escalate the issue to higher authorities (such as the head or vice president) or involve HR. I understand that this situation is not ideal as it can take time and potentially damage the team atmosphere. If I were in your position, I would initially try to find a compromise with the engineering manager and gradually asking for raising the standards for the role.</p><h2>Doesn&#8217;t Want to Grow</h2><h5>Question</h5><blockquote><p>I am a senior members in my team, there is a member (early mid-level) in my team doesn&#8217;t want to grow. have made several attempts to address this, such as providing examples and mapping out their weaknesses, but nothing has worked so far. But nothings worked. How to solve this issue?</p></blockquote><h5>Answer</h5><p>If a software engineer doesn't want to grow, then they will not grow regardless of your efforts. Instead of focusing on a growth strategy, it is important to understand why they are not interested in growth and what motivates them to work.</p><p>Do they truly <strong>dislike working as a software engineer</strong>? Do they have <strong>personal problems</strong> in their life? What are their <strong>career</strong> <strong>goals</strong>? Is it primarily <strong>driven by money</strong> or a desire for a <strong>higher position</strong>?</p><p>Until the reasons behind their lack of motivation are clear, there is no need to invest time in a growth strategy. It is crucial to ensure that they understand that growth is their own responsibility. During performance reviews, the results will indicate whether they are a good fit for the company. If they are not, they may choose to leave or be let go.</p><div><hr></div><p>Thank you for reading today's newsletter! If you find it valuable, don&#8217;t forget to:</p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe now&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.coderbased.com/subscribe?"><span>Subscribe now</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/til2-annoying-rockstar-useless-em?utm_source=substack&utm_medium=email&utm_content=share&action=share&quot;,&quot;text&quot;:&quot;Share&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.coderbased.com/p/til2-annoying-rockstar-useless-em?utm_source=substack&utm_medium=email&utm_content=share&action=share"><span>Share</span></a></p><p class="button-wrapper" data-attrs="{&quot;url&quot;:&quot;https://www.coderbased.com/p/til2-annoying-rockstar-useless-em/comments&quot;,&quot;text&quot;:&quot;Leave a comment&quot;,&quot;action&quot;:null,&quot;class&quot;:&quot;button-wrapper&quot;}" data-component-name="ButtonCreateButton"><a class="button primary button-wrapper" href="https://www.coderbased.com/p/til2-annoying-rockstar-useless-em/comments"><span>Leave a comment</span></a></p>]]></content:encoded></item></channel></rss>