<?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[Tech @ Yellow.ai ]]></title><description><![CDATA[Explore the forefront of conversational AI and innovation with the Yellow.ai Tech Blog. Delve into expert insights, behind-the-scenes stories, and the future of AI-powered conversations. Tech that powers the largest conversational ai platform.]]></description><link>https://tech.yellow.ai</link><image><url>https://substackcdn.com/image/fetch/$s_!GWcM!,w_256,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ff53da74e-d2b0-47f1-9a16-67d3e2aa7e6a_256x256.png</url><title>Tech @ Yellow.ai </title><link>https://tech.yellow.ai</link></image><generator>Substack</generator><lastBuildDate>Mon, 06 Apr 2026 12:00:47 GMT</lastBuildDate><atom:link href="https://tech.yellow.ai/feed" rel="self" type="application/rss+xml"/><copyright><![CDATA[Yellow AI ]]></copyright><language><![CDATA[en]]></language><webMaster><![CDATA[yellowaitech@substack.com]]></webMaster><itunes:owner><itunes:email><![CDATA[yellowaitech@substack.com]]></itunes:email><itunes:name><![CDATA[Jaya Kishore Reddy]]></itunes:name></itunes:owner><itunes:author><![CDATA[Jaya Kishore Reddy]]></itunes:author><googleplay:owner><![CDATA[yellowaitech@substack.com]]></googleplay:owner><googleplay:email><![CDATA[yellowaitech@substack.com]]></googleplay:email><googleplay:author><![CDATA[Jaya Kishore Reddy]]></googleplay:author><itunes:block><![CDATA[Yes]]></itunes:block><item><title><![CDATA[Boosting build speed by over 50% by migrating to Rsbuild]]></title><description><![CDATA[We migrated from Webpack to Rsbuild and saw a 50%+ boost in build speed. &#128640; This article covers the why, the how, and the results of our migration. If you're tired of slow builds, you need to read this.]]></description><link>https://tech.yellow.ai/p/boosting-build-speed-by-over-50-by</link><guid isPermaLink="false">https://tech.yellow.ai/p/boosting-build-speed-by-over-50-by</guid><dc:creator><![CDATA[Kanishka Chowdhury]]></dc:creator><pubDate>Mon, 08 Sep 2025 11:09:59 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!wZ4A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wZ4A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wZ4A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!wZ4A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!wZ4A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!wZ4A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wZ4A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg" width="1456" height="910" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:910,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Boosting build speed by over 50% by migrating to Rsbuild&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="Boosting build speed by over 50% by migrating to Rsbuild" title="Boosting build speed by over 50% by migrating to Rsbuild" srcset="https://substackcdn.com/image/fetch/$s_!wZ4A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg 424w, https://substackcdn.com/image/fetch/$s_!wZ4A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg 848w, https://substackcdn.com/image/fetch/$s_!wZ4A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!wZ4A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb537c7f1-cfcd-4d2a-b54c-1e4caa9ceb08_1600x1000.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><h2><strong>Introduction</strong></h2><p>In today's fast-paced development environment, build performance is crucial for developer productivity and deployment efficiency. Our team recently undertook a significant migration from Create React App (CRA) to <strong>Rsbuild</strong>, resulting in a remarkable <strong>50%+ improvement in build times</strong>. This blog post outlines our journey, the challenges we encountered, and the lessons we learned during this migration.</p><h2><strong>Overview of the current stack</strong></h2><h3><strong>Core Architecture</strong></h3><ul><li><p><strong>Micro Frontend Architecture</strong>: Built using <strong>Module Federation</strong> with multiple micro-frontends for different modules</p></li><li><p><strong>React 18</strong></p></li><li><p><strong>TypeScript</strong></p></li><li><p><strong>Create React App (CRA)</strong> with <strong>react-app-rewired</strong> for configuration overrides</p></li><li><p><strong>npm</strong> with <strong>Node.js 22.x</strong></p></li></ul><h3><strong>UI &amp; Styling</strong></h3><ul><li><p><strong>Design System</strong>: Custom design system built as a wrapper around <strong>Ant Design</strong></p></li><li><p><strong>Styling</strong>: <code>Less</code> preprocessor for AntD overrides and <strong>Tailwind</strong> for the main styling</p></li><li><p><strong>Monaco Editor</strong> for advanced code editing capabilities</p></li><li><p><strong>Day.js</strong> for lightweight date manipulation</p></li></ul><h3><strong>State Management &amp; Data</strong></h3><ul><li><p><strong>State Management</strong>: Redux with Redux Saga for side effects</p></li><li><p><strong>Data Fetching</strong>: TanStack React Query for server state management</p></li><li><p><strong>Internationalization</strong>: i18next for multi-language support</p></li></ul><h2><strong>Why We Needed This Migration?</strong></h2><h3><strong>The Problem with CRA</strong></h3><p>Our existing setup had several critical issues that were impacting our development workflow:</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tech.yellow.ai/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 Tech @ Yellow.ai ! 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><ol><li><p><strong>CRA Deprecation</strong>: Create React App is officially deprecated, meaning no new features or security updates</p></li><li><p><strong>Slow Build Times</strong>: Our webpack-based builds were taking an average of <strong>15 minutes</strong> to complete</p></li><li><p><strong>Bloated Configuration</strong>: Complex webpack overrides using react-app-rewired were becoming unmaintainable</p></li></ol><h3><strong>Impact</strong></h3><ul><li><p><strong>Customer Impact</strong>: Delays in fixing bugs due to slow build times were affecting customers. This led to frustration and a decrease in user satisfaction, as customers had to wait longer for improvements/fixes.</p></li><li><p><strong>Developer Productivity</strong>: Long build times significantly reduce developer velocity</p></li></ul><h2><strong>Why We Chose Rsbuild?</strong></h2><p>After evaluating several alternatives, we chose <strong><a href="https://rsbuild.rs/">Rsbuild</a></strong> for the following reasons:</p><h3><strong>1. Performance Benefits</strong></h3><ul><li><p><strong>Rust-based Rspack</strong>: Underlying bundler written in Rust, providing ~50% faster builds compared to webpack</p></li><li><p><strong>Optimized Architecture</strong>: Built specifically for modern web development with performance in mind</p></li></ul><h3><strong>2. Seamless Migration Path</strong></h3><ul><li><p><strong>Webpack Compatibility</strong>: Rspack offers a webpack-compatible API, making migration smoother, and most popular webpack plugins are already supported</p></li><li><p><strong>CRA Migration Guide</strong>: Comprehensive migration documentation available at <strong><a href="https://rsbuild.rs/guide/migration/cra">rsbuild.rs/guide/migration/cra</a></strong></p></li></ul><h3><strong>3. Out-of-the-Box Features</strong></h3><ul><li><p><strong>Module Federation</strong>: Native support for micro-frontend architecture</p></li><li><p><strong>Less Support</strong>: Built-in Less preprocessor support</p></li><li><p><strong>Tree Shaking &amp; Code Splitting</strong>: Advanced optimization features</p></li><li><p><strong>TypeScript</strong>: First-class TypeScript support</p></li></ul><h3><strong>4. Future-Proof Architecture</strong></h3><ul><li><p><strong>Plugin-based System</strong>: Extensible architecture for future enhancements</p></li><li><p><strong>Active community</strong>: Regular updates and active community support (<strong>300k+</strong> weekly downloads)</p></li><li><p><strong>Modern Tooling</strong>: Built for the modern web development ecosystem</p></li></ul><h2><strong>Migration Plan &amp; Strategy</strong></h2><h3><strong>Phase 1: Foundation Setup</strong></h3><p>Following the <strong><a href="https://rsbuild.rs/guide/migration/cra">official Rsbuild CRA migration guide</a></strong>, we:</p><ol><li><p><strong>Replaced Dependencies</strong>:</p></li></ol><pre><code><code>npm remove react-scripts  
npm add @rsbuild/core @rsbuild/plugin-react -D </code></code></pre><ol><li><p><strong>Updated Scripts</strong>:</p></li></ol><pre><code><code>{
  "scripts": {
    "start": "rsbuild dev",
    "build": "rsbuild build",
    "preview": "rsbuild preview"
  }
}</code></code></pre><ol><li><p><strong>Created Configuration</strong>:</p></li></ol><pre><code><code> // rsbuild.config.ts
 import { defineConfig } from '@rsbuild/core';
 import { pluginReact } from '@rsbuild/plugin-react';

 export default defineConfig({
   plugins: [pluginReact()],
 });</code></code></pre><h3><strong>Phase 2: Plugin Migration Analysis</strong></h3><p>We identified and migrated our webpack plugins:</p><p><strong>Removed Plugins</strong> (native Rsbuild support):</p><ul><li><p><code>babel-plugin-transform-remove-console</code> &#8594; <code>performance.removeConsole</code></p></li><li><p><code>worker-loader</code> &#8594; Native web worker support</p></li></ul><p><strong>Migrated Plugins</strong>:</p><ul><li><p>Module Federation &#8594; <code>@module-federation/rsbuild-plugin</code></p></li><li><p>Less loader &#8594; <code>@rsbuild/plugin-less</code></p></li><li><p>Node polyfills &#8594; <code>@rsbuild/plugin-node-polyfill</code></p></li></ul><h3><strong>Phase 3: Staged Rollout</strong></h3><ul><li><p><strong>Staging Environment</strong>: Deployed changes to staging for initial testing</p></li><li><p><strong>Beta Environment</strong>: Extended testing in the beta environment</p></li><li><p><strong>Traffic Analysis</strong>: Monitored for one week to identify potential issues</p></li><li><p><strong>Production Deployment</strong>: Gradual rollout to production</p></li></ul><h2><strong>Challenges Faced &amp; Solutions</strong></h2><h3><strong>1. Plugin and Loader Compatibility</strong></h3><ul><li><p><strong>Challenge:</strong> Not all webpack plugins or loaders are directly compatible with Rsbuild/Rspack.</p></li><li><p><strong>Guideline:</strong> Audit your current plugins and loaders, and check for native support or recommended alternatives in Rsbuild. Be prepared to refactor or remove plugins that are no longer necessary or supported.</p></li><li><p><strong>Example:</strong> We found that plugins like <code>babel-plugin-transform-remove-console</code> and <code>worker-loader</code> were no longer needed, as Rsbuild provided native support for these features.</p></li></ul><h3><strong>2. Styling and CSS Handling</strong></h3><ul><li><p><strong>Challenge:</strong> Differences in how CSS modules, preprocessors (like Less), and global styles are handled can lead to unexpected styling issues.</p></li><li><p><strong>Guideline:</strong> Review your styling approach, especially for global overrides and CSS module conventions. Test your styles thoroughly after migration and adjust configurations as needed.</p></li><li><p><strong>Example:</strong> Some global <code>Less</code> overrides for Ant Design were not being applied as expected due to differences in how global selectors were processed, which required us to adjust our style definitions and loader settings.</p></li></ul><h3><strong>3. Micro-Frontend Integration</strong></h3><ul><li><p><strong>Challenge:</strong> Ensuring consistent and singleton usage of shared dependencies across micro-frontends is critical to avoid runtime issues.</p></li><li><p><strong>Guideline:</strong> Align dependency versions and configurations across all MFEs, and use best practices for sharing libraries and assets.</p></li><li><p><strong>Example:</strong> We encountered issues with multiple instances of libraries like <code>dayjs</code> being loaded in different MFEs, which led to inconsistent behavior in date pickers.</p></li></ul><h3><strong>4. Third-Party Library Support</strong></h3><ul><li><p><strong>Challenge:</strong> Some third-party libraries or plugins may not work out of the box with Rsbuild.</p></li><li><p><strong>Guideline:</strong> Check the compatibility of critical libraries early in the migration process. Look for modern, actively maintained alternatives if needed, and plan for isolated testing of such dependencies.</p></li><li><p><strong>Example:</strong> Our existing code editor integration relied on a plugin that was not compatible with Rsbuild, prompting us to migrate to a newer, supported alternative.</p></li></ul><h2><strong>Deployment Strategy &#128640;</strong></h2><h3><strong>Pre-Migration Preparation</strong></h3><p>Before starting the Rsbuild migration, we established a comprehensive deployment strategy to ensure minimal disruption:</p><h3><strong>Staged Deployment Approach</strong></h3><h4><strong>Phase 1: Internal Testing (Week 1-2)</strong></h4><ul><li><p>We first tested the <code>Rsbuild</code> changes in the <strong>local</strong> dev server</p></li><li><p>Comprehensive testing across all features and user flows</p></li><li><p><strong>Performance Benchmarking</strong>: Measured build times, bundle sizes, and runtime performance</p></li></ul><h4><strong>Phase 2: Staging Environment (Week 3)</strong></h4><ul><li><p>Deployed the <code>Rsbuild</code> version to the <strong>staging</strong> environment</p></li><li><p><strong>QA Testing:</strong> Manual QA testing and automation suites were run to identify any issues.</p></li><li><p><strong>Integration Testing</strong>: Verified all micro-frontend integrations worked correctly</p></li></ul><h4><strong>Phase 3: Beta Environment (Week 4)</strong></h4><ul><li><p>Deployed the <code>Rsbuild</code> version to the <strong>beta</strong> environment</p></li><li><p><strong>QA Testing:</strong> Manual QA testing and automation suites were run on more production-level data.</p></li><li><p><strong>Error Rate Monitoring</strong>: Closely monitored error rates and performance metrics</p></li></ul><h4><strong>Phase 4: Production Rollout (Week 5)</strong></h4><ul><li><p><strong>Maintenance window</strong>: Although we did not expect any downtime with this migration, we decided to provide a maintenance window communication to ensure safety and a better customer experience. The maintenance window was strategically chosen by analyzing user traffic data to ensure it&#8217;s during non-critical business hours.</p></li><li><p><strong>Real-time Monitoring</strong>: Continuous error monitoring during the rollout period</p></li><li><p><strong>Rollback plan</strong>: We already have a rollback strategy for deployments, so we decided to stick with it.</p></li></ul><h3><strong>Post-Deployment Validation</strong></h3><h4><strong>Automated Health Checks</strong></h4><ul><li><p><strong>Smoke Tests</strong>: Automated tests for critical user flows</p></li><li><p><strong>Performance Tests</strong>: Automated performance regression tests</p></li></ul><h4><strong>Manual Validation Checklist</strong></h4><ul><li><p>All major user flows work correctly</p></li><li><p>Performance metrics meet or exceed baseline</p></li><li><p>Error rates remain within acceptable thresholds</p></li><li><p>All integrations (APIs, third-party services) function properly</p></li></ul><h3><strong>Lessons Learned from Deployment</strong></h3><h4><strong>What Went Well</strong></h4><ul><li><p><strong>Staged Approach</strong>: Gradual rollout helped identify issues early</p></li><li><p><strong>Monitoring</strong>: Comprehensive monitoring caught issues before they affected users</p></li><li><p><strong>Rollback Plan</strong>: Having a solid rollback strategy provided confidence during deployment</p></li></ul><h4><strong>Areas for Improvement</strong></h4><ul><li><p><strong>Testing Coverage</strong>: Could have benefited from more automated integration tests</p></li><li><p><strong>Performance Baselines</strong>: Should have established clearer performance benchmarks</p></li><li><p><strong>Communication</strong>: Could have improved stakeholder communication during the rollout</p></li></ul><h2><strong>Results &#127881;</strong></h2><h3><strong>Build Time Improvements</strong></h3><p><strong>Production Build</strong>: Reduced from <strong>~8 minutes</strong> to <strong>~3 minutes</strong> (<strong>&gt;60%</strong> improvement)</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!F9Sm!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4def38a3-9bd4-43a5-b098-496dab7ed8e3_1310x743.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!F9Sm!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4def38a3-9bd4-43a5-b098-496dab7ed8e3_1310x743.png 424w, https://substackcdn.com/image/fetch/$s_!F9Sm!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4def38a3-9bd4-43a5-b098-496dab7ed8e3_1310x743.png 848w, https://substackcdn.com/image/fetch/$s_!F9Sm!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4def38a3-9bd4-43a5-b098-496dab7ed8e3_1310x743.png 1272w, https://substackcdn.com/image/fetch/$s_!F9Sm!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4def38a3-9bd4-43a5-b098-496dab7ed8e3_1310x743.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!F9Sm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4def38a3-9bd4-43a5-b098-496dab7ed8e3_1310x743.png" width="1310" height="743" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4def38a3-9bd4-43a5-b098-496dab7ed8e3_1310x743.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:743,&quot;width&quot;:1310,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!F9Sm!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4def38a3-9bd4-43a5-b098-496dab7ed8e3_1310x743.png 424w, https://substackcdn.com/image/fetch/$s_!F9Sm!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4def38a3-9bd4-43a5-b098-496dab7ed8e3_1310x743.png 848w, https://substackcdn.com/image/fetch/$s_!F9Sm!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4def38a3-9bd4-43a5-b098-496dab7ed8e3_1310x743.png 1272w, https://substackcdn.com/image/fetch/$s_!F9Sm!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4def38a3-9bd4-43a5-b098-496dab7ed8e3_1310x743.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><strong>Developer Experience</strong></h3><ul><li><p><strong>Faster Feedback Loop</strong>: Quicker development iterations</p></li></ul><h2><strong>Conclusion</strong></h2><p>Our migration from CRA to Rsbuild was a significant success, resulting in <strong>50%+ improvement in build times</strong> and a more modern, maintainable build system. While the migration presented several challenges, the benefits far outweighed the effort:</p><ul><li><p><strong>Faster Development</strong>: Reduced build times significantly improved developer productivity</p></li><li><p><strong>Modern Tooling</strong>: Access to the latest web development features and optimizations</p></li><li><p><strong>Future-Proof</strong>: Active development and community support ensure long-term viability</p></li></ul><p>The key to success was a well-planned migration strategy, thorough testing, and addressing issues incrementally. For teams considering similar migrations, we recommend:</p><ol><li><p><strong>Start with the official migration guide</strong></p></li><li><p><strong>Plan for plugin compatibility issues</strong></p></li><li><p><strong>Implement a staged rollout strategy</strong></p></li><li><p><strong>Monitor performance metrics throughout</strong></p></li><li><p><strong>Have rollback plans ready</strong></p></li></ol><p>The migration has positioned our team for better performance, faster development cycles, and access to modern web development tools. The investment in migration has already paid dividends in improved developer experience and deployment efficiency.</p><h3><strong>What's Next?</strong></h3><p>Here are some of the next steps we are considering:</p><ol><li><p><strong>Adopting Faster Package Managers</strong></p><ul><li><p>We are exploring switching from <code>npm</code> to <code>pnpm</code> for dependency management.</p></li></ul></li><li><p><strong>Optimizing Dependencies</strong></p><ul><li><p>Regularly audit and prune unused dependencies/code, and consider splitting large dependencies or lazy-loading rarely used modules to keep the build lean.</p></li></ul></li><li><p><strong>Fine-Tuning Module Federation</strong></p><ul><li><p>Analyze our micro-frontend boundaries and shared dependencies to ensure optimal code splitting and minimal duplication across MFEs, reducing both build and runtime bundle sizes.</p></li></ul></li><li><p><strong>Parallelizing CI/CD Steps</strong></p><ul><li><p>Refactor CI/CD pipelines to maximize parallelism, such as running linting, testing, and building steps concurrently where possible.</p></li></ul></li><li><p><strong>Profiling and Monitoring</strong></p><ul><li><p>Continuously profile build performance using tools like <strong><a href="https://www.npmjs.com/package/webpack-bundle-analyzer">Webpack Bundle Analyzer</a></strong> or Rsbuild&#8217;s <strong><a href="https://rsdoctor.rs/">Rsdoctor</a></strong> to identify new bottlenecks as the codebase evolves.</p></li></ul></li></ol><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tech.yellow.ai/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 Tech @ Yellow.ai ! 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>]]></content:encoded></item><item><title><![CDATA[Komodo-7B: The First LLM for Regional Languages in Indonesia]]></title><description><![CDATA[Motivation]]></description><link>https://tech.yellow.ai/p/komodo-7b-the-first-llm-for-regional</link><guid isPermaLink="false">https://tech.yellow.ai/p/komodo-7b-the-first-llm-for-regional</guid><dc:creator><![CDATA[Louis Owen]]></dc:creator><pubDate>Tue, 26 Mar 2024 13:14:39 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!TLTg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!TLTg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!TLTg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.png 424w, https://substackcdn.com/image/fetch/$s_!TLTg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.png 848w, https://substackcdn.com/image/fetch/$s_!TLTg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.png 1272w, https://substackcdn.com/image/fetch/$s_!TLTg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!TLTg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.png" width="1456" height="817" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:817,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!TLTg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.png 424w, https://substackcdn.com/image/fetch/$s_!TLTg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.png 848w, https://substackcdn.com/image/fetch/$s_!TLTg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.png 1272w, https://substackcdn.com/image/fetch/$s_!TLTg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F18cbce1c-aeec-4d8b-b8db-79a5a872b44f_1600x898.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><h1>Motivation</h1><p>The recent advancements in Large Language Models (LLMs) have mostly focused on languages like English with plenty of resources available. But there's still a big gap for languages that don't have enough resources published. While models like GPT-3.5, GPT-4 and Llama-2 perform well in various tasks, they are primarily evaluated in English and tend to struggle with languages other than English. On the other hand, there are multilingual models like Aya-101, Bactrian-X, Qwen-1.5, and Mixtral, which excel in tasks involving multiple languages. However, when it comes to individual languages or small regional languages with limited data, these models lack specialized expertise.</p><p>This performance gap underscores the need for focused attention and improvement in addressing the specific challenges posed by Indonesian and regional languages in the realm of language models. Currently, there is a notable absence of high-performing LLMs specifically designed for Indonesia, trained on Indonesian data, and evaluated against benchmarks for Indonesia&#8217;s regional languages.&nbsp;</p><h1>Introducing Komodo-7B</h1><p>In response to this, we are proud to introduce Komodo-7B, a Large Language Model with 7 billion parameters, designed to fill this gap. It can seamlessly work with Indonesian, English, and 11 other regional languages in Indonesia. Komodo-7B&#8217;s ability to understand different languages helps address educational disparities in Indonesia by offering direct translations from English to 11 regional languages of Indonesia. This is a big improvement over Google Translate which supports only 4 languages: Indonesian, English, Javanese, and Sundanese.</p><p>With Komodo-7B, businesses can now support customers from various parts of Indonesia without needing to hire agents who speak every regional language in Indonesia. For instance, if a customer speaks Lampungnese and the agent speaks Javanese, Komodo-7B can bridge the communication gap. It&#8217;s time to say goodbye to language barriers in customer service.</p><p>Besides translation, Komodo-7B is also capable of performing a wide range of tasks, including but not limited to intent classification, sentiment analysis, common sense reasoning, and any other use cases. In fact, it&#8217;s able to support any task that we want to focus on by fine-tuning the base model on that specific use case.&nbsp;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!vcpX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e474cf6-6884-41e1-96c4-c1c03f9da4e7_1600x914.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!vcpX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e474cf6-6884-41e1-96c4-c1c03f9da4e7_1600x914.png 424w, https://substackcdn.com/image/fetch/$s_!vcpX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e474cf6-6884-41e1-96c4-c1c03f9da4e7_1600x914.png 848w, https://substackcdn.com/image/fetch/$s_!vcpX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e474cf6-6884-41e1-96c4-c1c03f9da4e7_1600x914.png 1272w, https://substackcdn.com/image/fetch/$s_!vcpX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e474cf6-6884-41e1-96c4-c1c03f9da4e7_1600x914.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!vcpX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e474cf6-6884-41e1-96c4-c1c03f9da4e7_1600x914.png" width="1456" height="832" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8e474cf6-6884-41e1-96c4-c1c03f9da4e7_1600x914.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:832,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!vcpX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e474cf6-6884-41e1-96c4-c1c03f9da4e7_1600x914.png 424w, https://substackcdn.com/image/fetch/$s_!vcpX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e474cf6-6884-41e1-96c4-c1c03f9da4e7_1600x914.png 848w, https://substackcdn.com/image/fetch/$s_!vcpX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e474cf6-6884-41e1-96c4-c1c03f9da4e7_1600x914.png 1272w, https://substackcdn.com/image/fetch/$s_!vcpX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8e474cf6-6884-41e1-96c4-c1c03f9da4e7_1600x914.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>Developing Komodo-7B was not an easy task that involved using a huge amount of training data and extensive preprocessing to create a high-quality dataset. As the name suggests, Komodo-7B has 7 billion parameters and is trained on over 8.5 billion tokens. To put this into perspective, 8.5 billion tokens is equivalent to more than 20 gigabytes of data. The result is a groundbreaking model that performs exceptionally well in Indonesian and regional languages.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!mdft!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b955c5d-93de-49b2-a6fc-640bc1747350_1282x534.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!mdft!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b955c5d-93de-49b2-a6fc-640bc1747350_1282x534.png 424w, https://substackcdn.com/image/fetch/$s_!mdft!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b955c5d-93de-49b2-a6fc-640bc1747350_1282x534.png 848w, https://substackcdn.com/image/fetch/$s_!mdft!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b955c5d-93de-49b2-a6fc-640bc1747350_1282x534.png 1272w, https://substackcdn.com/image/fetch/$s_!mdft!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b955c5d-93de-49b2-a6fc-640bc1747350_1282x534.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!mdft!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b955c5d-93de-49b2-a6fc-640bc1747350_1282x534.png" width="1282" height="534" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6b955c5d-93de-49b2-a6fc-640bc1747350_1282x534.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:534,&quot;width&quot;:1282,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!mdft!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b955c5d-93de-49b2-a6fc-640bc1747350_1282x534.png 424w, https://substackcdn.com/image/fetch/$s_!mdft!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b955c5d-93de-49b2-a6fc-640bc1747350_1282x534.png 848w, https://substackcdn.com/image/fetch/$s_!mdft!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b955c5d-93de-49b2-a6fc-640bc1747350_1282x534.png 1272w, https://substackcdn.com/image/fetch/$s_!mdft!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6b955c5d-93de-49b2-a6fc-640bc1747350_1282x534.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>Komodo-7B itself is a family of LLMs that consists of Komodo-7B-Base and Komodo-7B-Instruct.&nbsp;</p><ul><li><p>Komodo-7B-Base is a large language model that is developed through incremental pretraining and vocabulary expansion on top of Llama-2-7B-Base.&nbsp;</p></li><li><p>Komodo-7B-Instruct is the fine-tuned version of Komodo-7B-Base that has been trained to understand a wide range of instructions.</p></li></ul><h2>Training Data</h2><p>The dataset employed in both the pre-training and fine-tuning phases of our language model was created not only from diverse open-source datasets but also from manually collected data. Additionally, we made use of freely available datasets primarily collected in Indonesian and other regional languages, such as Javanese, Sundanese, Acehnese, and many more. We aim to ensure that our language model is well-versed not only in Indonesian but also in other regional languages. This approach helps improve the model&#8217;s overall language skills and adaptability to various cultural contexts.</p><h2>Vocabulary Expansion</h2><p>As a reminder, tokenizer is a crucial component that breaks down input text into smaller units called tokens. These tokens are the basic building blocks that the model uses to understand and generate text. Recognizing the importance of linguistic diversity, we focused on enhancing our language model&#8217;s proficiency in both Indonesian and regional languages. To achieve this, we systematically expanded the tokenizer&#8217;s vocabulary by identifying and incorporating approximately 2,000 frequently used words specific to Indonesian and 1,000 words for Indonesia&#8217;s regional languages that were absent in the Llama-2 model.</p><p>The standard method for improving vocabulary in language models typically involves training a new tokenizer and merging it with the existing one. This approach has shown impressive results in projects like <a href="https://arxiv.org/abs/2304.08177">Chinese-LLaMA</a> and <a href="https://www.sarvam.ai/blog/announcing-openhathi-series">Open-Hathi</a>. The effectiveness of this strategy can be attributed to the significant linguistic differences between languages such as Chinese and Hindi compared to English. In contrast, the Indonesian and regional languages use the same Latin script as English, which presents a different set of challenges.</p><p>We tested the traditional method, as well as a new approach where we added the top n words (not tokens) from the Indonesian and regional languages vocabulary without training any new tokenizer. We discovered that with the new approach, we could achieve better fertility scores by adding around 3000 new vocabulary words. Adding more than 3000 words did not significantly improve the fertility score further, but it increased the size of the embedding matrix, leading to longer training times. Note that fertility score refers to the ability of a tokenizer to break down text into meaningful units (tokens) while minimizing the number of unique tokens required.&nbsp;</p><h2>Incremental Pretraining &amp; Fine-Tuning</h2><p>For pretraining, our tokenizer processed approximately 8.79 billion tokens. We conducted incremental pretraining, building upon Llama-2-7B-Base, over 3 epochs using LORA. This approach helps prevent catastrophic forgetting and optimizes hardware and cost requirements. The training utilized 8 x A100 40GB GPUs and took approximately 300 hours. We further refined our model through Supervised Fine-Tuning (SFT) on diverse tasks for 5 epochs using LORA. Employing the same GPU configuration, the SFT process took about 36 hours.</p><h1>Evaluation &amp; Results</h1><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!kgAk!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc76c20f2-412e-4d5a-8a9c-c8f828119e43_1424x1170.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!kgAk!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc76c20f2-412e-4d5a-8a9c-c8f828119e43_1424x1170.png 424w, https://substackcdn.com/image/fetch/$s_!kgAk!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc76c20f2-412e-4d5a-8a9c-c8f828119e43_1424x1170.png 848w, https://substackcdn.com/image/fetch/$s_!kgAk!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc76c20f2-412e-4d5a-8a9c-c8f828119e43_1424x1170.png 1272w, https://substackcdn.com/image/fetch/$s_!kgAk!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc76c20f2-412e-4d5a-8a9c-c8f828119e43_1424x1170.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!kgAk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc76c20f2-412e-4d5a-8a9c-c8f828119e43_1424x1170.png" width="1424" height="1170" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c76c20f2-412e-4d5a-8a9c-c8f828119e43_1424x1170.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1170,&quot;width&quot;:1424,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!kgAk!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc76c20f2-412e-4d5a-8a9c-c8f828119e43_1424x1170.png 424w, https://substackcdn.com/image/fetch/$s_!kgAk!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc76c20f2-412e-4d5a-8a9c-c8f828119e43_1424x1170.png 848w, https://substackcdn.com/image/fetch/$s_!kgAk!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc76c20f2-412e-4d5a-8a9c-c8f828119e43_1424x1170.png 1272w, https://substackcdn.com/image/fetch/$s_!kgAk!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc76c20f2-412e-4d5a-8a9c-c8f828119e43_1424x1170.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>We evaluated Komodo-7B-Instruct against multiple open-source and closed-source massively multilingual models to ensure comprehensive evaluations. As can be seen from the above figure, Komodo-7B-Instruct outperforms all other &#8220;strong&#8221; open-source models as well as GPT3.5 in both generative and discriminative tasks that are benchmarked by us.&nbsp;</p><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!LGgy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92785630-26d6-4939-b8ea-a44a72cea014_1302x218.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!LGgy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92785630-26d6-4939-b8ea-a44a72cea014_1302x218.png 424w, https://substackcdn.com/image/fetch/$s_!LGgy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92785630-26d6-4939-b8ea-a44a72cea014_1302x218.png 848w, https://substackcdn.com/image/fetch/$s_!LGgy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92785630-26d6-4939-b8ea-a44a72cea014_1302x218.png 1272w, https://substackcdn.com/image/fetch/$s_!LGgy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92785630-26d6-4939-b8ea-a44a72cea014_1302x218.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!LGgy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92785630-26d6-4939-b8ea-a44a72cea014_1302x218.png" width="1302" height="218" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/92785630-26d6-4939-b8ea-a44a72cea014_1302x218.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:218,&quot;width&quot;:1302,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!LGgy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92785630-26d6-4939-b8ea-a44a72cea014_1302x218.png 424w, https://substackcdn.com/image/fetch/$s_!LGgy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92785630-26d6-4939-b8ea-a44a72cea014_1302x218.png 848w, https://substackcdn.com/image/fetch/$s_!LGgy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92785630-26d6-4939-b8ea-a44a72cea014_1302x218.png 1272w, https://substackcdn.com/image/fetch/$s_!LGgy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F92785630-26d6-4939-b8ea-a44a72cea014_1302x218.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a></figure></div><p>Komodo-7B also offers lower inference cost, by up to 30%, since it requires less amount of tokens compared to Llama-2-7B to complete one sentence, as measured by the fertility score. When comparing the tokenizer performance between Llama-2-7B, our baseline model, and Komodo-7B, the enhanced version, notable distinctions emerge as shown in the above table. Llama-2-7B showcases mean fertility scores of 2.858 for Indonesian, 2.658 for regional languages of Indonesia, and 1.666 for English, with a vocabulary size of 32,000. On the other hand, Komodo-7B exhibits substantial improvements with mean fertility scores of 2.031 for Indonesian, 1.996 for regional languages of Indonesia, and 1.633 for English, coupled with an expanded vocabulary size of 35,008.&nbsp;</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!6ut3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F611c1a1d-f519-4334-a8ea-cef452638003_1232x590.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!6ut3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F611c1a1d-f519-4334-a8ea-cef452638003_1232x590.png 424w, https://substackcdn.com/image/fetch/$s_!6ut3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F611c1a1d-f519-4334-a8ea-cef452638003_1232x590.png 848w, https://substackcdn.com/image/fetch/$s_!6ut3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F611c1a1d-f519-4334-a8ea-cef452638003_1232x590.png 1272w, https://substackcdn.com/image/fetch/$s_!6ut3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F611c1a1d-f519-4334-a8ea-cef452638003_1232x590.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!6ut3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F611c1a1d-f519-4334-a8ea-cef452638003_1232x590.png" width="1232" height="590" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/611c1a1d-f519-4334-a8ea-cef452638003_1232x590.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:590,&quot;width&quot;:1232,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!6ut3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F611c1a1d-f519-4334-a8ea-cef452638003_1232x590.png 424w, https://substackcdn.com/image/fetch/$s_!6ut3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F611c1a1d-f519-4334-a8ea-cef452638003_1232x590.png 848w, https://substackcdn.com/image/fetch/$s_!6ut3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F611c1a1d-f519-4334-a8ea-cef452638003_1232x590.png 1272w, https://substackcdn.com/image/fetch/$s_!6ut3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F611c1a1d-f519-4334-a8ea-cef452638003_1232x590.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 above figure provides a valuable analysis for evaluating the translation capabilities of Komodo-7B-Instruct compared to Google Translate. The visual representation helps us see the languages each platform supports. The heatmap on the right side illustrates Google Translate's proficiency, especially in Javanese, English, Indonesian, and Sundanese. However, it also shows that there are many language spaces left unoccupied.</p><p>Conversely, the left side of the heatmap showcases the comprehensive linguistic capabilities of Komodo-7B-Instruct, encompassing a total of 11 Indonesia&#8217;s regional languages. This inclusive approach extends the reach of education in Indonesia by enabling direct translation from English to a diverse range of Indonesia&#8217;s regional languages including languages that are not supported by many models and translation systems like Acehnese, Balinese, Banjarese, Buginese, Madurese, Minangkabau, and Toba Batak.</p><p>The broader coverage of Komodo-7B-Instruct ensures that individuals across various regions in Indonesia, beyond Java, can benefit from education in their native languages. This not only enhances accessibility but also addresses the challenge of language diversity in educational settings. Therefore, Komodo-7B-Instruct stands as a promising solution for bridging educational gaps and encouraging inclusivity in language learning.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!RQv4!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf5a2cc5-d224-43ef-a93c-66007a79f87b_1600x898.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!RQv4!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf5a2cc5-d224-43ef-a93c-66007a79f87b_1600x898.png 424w, https://substackcdn.com/image/fetch/$s_!RQv4!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf5a2cc5-d224-43ef-a93c-66007a79f87b_1600x898.png 848w, https://substackcdn.com/image/fetch/$s_!RQv4!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf5a2cc5-d224-43ef-a93c-66007a79f87b_1600x898.png 1272w, https://substackcdn.com/image/fetch/$s_!RQv4!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf5a2cc5-d224-43ef-a93c-66007a79f87b_1600x898.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!RQv4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf5a2cc5-d224-43ef-a93c-66007a79f87b_1600x898.png" width="1456" height="817" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bf5a2cc5-d224-43ef-a93c-66007a79f87b_1600x898.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:817,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!RQv4!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf5a2cc5-d224-43ef-a93c-66007a79f87b_1600x898.png 424w, https://substackcdn.com/image/fetch/$s_!RQv4!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf5a2cc5-d224-43ef-a93c-66007a79f87b_1600x898.png 848w, https://substackcdn.com/image/fetch/$s_!RQv4!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf5a2cc5-d224-43ef-a93c-66007a79f87b_1600x898.png 1272w, https://substackcdn.com/image/fetch/$s_!RQv4!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbf5a2cc5-d224-43ef-a93c-66007a79f87b_1600x898.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 addition to quantitative benchmarking, we conducted qualitative testing by providing various general instructions to the model. Figure 7 displays a sample of these instructions along with the responses from Llama-2-7B-Finetuned and Gemma-7B-Finetuned. It is worth noting that both Llama-2-7B-Finetuned and Gemma-7B-Finetuned were trained on the same data as Komodo-7B-Instruct.</p><p>Here, we ask each of the models to perform sentiment analysis where the input sentence is &#8220;Aya naon iye teh, gx kkirim2 duit nya?&#8221;, which means &#8220;What&#8217;s actually the problem? my money has not been transferred yet&#8221;. Note that the sentence is written in a slang version of Indonesian mixed with Sundanese, one of Indonesia's regional languages. The correct intent for the given sentence is &#8220;kendala transaksi&#8221;, which means &#8220;transaction issue&#8221;, while the rest of the intent options are &#8220;kembalikan uang&#8221;, &#8220;kembalikan barang&#8221;, and &#8220;tidak ada&#8221;, which means &#8220;money refund&#8221;, &#8220;item return&#8221;, and &#8220;none&#8221;, respectively.</p><p>As can be seen, both Llama-2-7B-Finetuned and Gemma-7B-Finetuned return wrong intents while Komodo-7B-Instruct successfully returns the correct intent.</p><h1>Future Works</h1><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0O5w!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c82925e-e4dd-4e0b-81d2-de46779612b7_1600x904.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0O5w!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c82925e-e4dd-4e0b-81d2-de46779612b7_1600x904.png 424w, https://substackcdn.com/image/fetch/$s_!0O5w!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c82925e-e4dd-4e0b-81d2-de46779612b7_1600x904.png 848w, https://substackcdn.com/image/fetch/$s_!0O5w!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c82925e-e4dd-4e0b-81d2-de46779612b7_1600x904.png 1272w, https://substackcdn.com/image/fetch/$s_!0O5w!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c82925e-e4dd-4e0b-81d2-de46779612b7_1600x904.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0O5w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c82925e-e4dd-4e0b-81d2-de46779612b7_1600x904.png" width="1456" height="823" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/6c82925e-e4dd-4e0b-81d2-de46779612b7_1600x904.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:823,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0O5w!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c82925e-e4dd-4e0b-81d2-de46779612b7_1600x904.png 424w, https://substackcdn.com/image/fetch/$s_!0O5w!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c82925e-e4dd-4e0b-81d2-de46779612b7_1600x904.png 848w, https://substackcdn.com/image/fetch/$s_!0O5w!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c82925e-e4dd-4e0b-81d2-de46779612b7_1600x904.png 1272w, https://substackcdn.com/image/fetch/$s_!0O5w!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F6c82925e-e4dd-4e0b-81d2-de46779612b7_1600x904.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 the future, we plan to enhance the capabilities of Komodo-7B-Instruct by training task-specific large language models (LLMs) on top of the existing Komodo-7B-Base model. While the current model performs well across a wide range of instructions, the task-specific models will be tailored to excel in their respective tasks. For example, there will be a model trained specifically for Question Answering tasks, Intent Classification tasks, and many more. This approach is expected to further improve the model's performance, making it even more suitable for production use.&nbsp;</p><p>We also plan to further enhance Komodo-7B-Instruct by creating a conversational variant of the model. This iteration will be trained to comprehend not only single-turn but also multi-turn conversations, enabling it to grasp the context of a dialogue. By enhancing the model's capacity to understand conversational nuances, we anticipate improving its capability to deliver accurate and contextually relevant responses.</p><p>Finally, we also aim to train an even larger version of Komodo, potentially with 13B, 33B, or even 70B parameters! This endeavor is driven by the aspiration to enhance the model's quality by having more parameters.</p><h1>Paper and Model Release</h1><ul><li><p>For further insights, we encourage you to explore the research paper on <strong>ArXiv</strong> via the following link:<a href="https://arxiv.org/abs/2403.09362"> Link to the research paper</a>.&nbsp;</p></li><li><p>Additionally, you can access the Komodo-7B-Base model on <strong>Hugging Face</strong>'s model hub:<a href="https://huggingface.co/Yellow-AI-NLP/komodo-7b-base"> Link to Komodo-7B on Hugging Face</a>.</p></li></ul>]]></content:encoded></item><item><title><![CDATA[Effortless Multi-cloud Management: Secure Access to VMs and Kubernetes Workloads]]></title><description><![CDATA[SSH(Secure Shell) is one of the most ubiquitous tools in the modern computing world.]]></description><link>https://tech.yellow.ai/p/effortless-multi-cloud-management</link><guid isPermaLink="false">https://tech.yellow.ai/p/effortless-multi-cloud-management</guid><dc:creator><![CDATA[Nikhil M]]></dc:creator><pubDate>Thu, 08 Feb 2024 05:05:47 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!0WSa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0WSa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0WSa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512 424w, https://substackcdn.com/image/fetch/$s_!0WSa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512 848w, https://substackcdn.com/image/fetch/$s_!0WSa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512 1272w, https://substackcdn.com/image/fetch/$s_!0WSa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0WSa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512" width="512" height="512" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:512,&quot;width&quot;:512,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0WSa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512 424w, https://substackcdn.com/image/fetch/$s_!0WSa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512 848w, https://substackcdn.com/image/fetch/$s_!0WSa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512 1272w, https://substackcdn.com/image/fetch/$s_!0WSa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F60bfcb38-2133-4ebb-91f5-a621d2dfeb9d_800x512 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"></figcaption></figure></div><p><strong>SSH(</strong><em>Secure Shell</em><strong>)</strong> is one of the most ubiquitous tools in the modern computing world. It has been around for a long time and commonly used on all Linux machines. While it works really well, there are some operational burdens and security concerns that comes with it such as -</p><ol><li><p>Opening SSH ports to the target <strong>VM(</strong><em>Virtual Machine</em><strong>).</strong></p></li><li><p>SSH key management including a list of who has access to which VMs.</p></li><li><p>What commands are people running on the VMs when they access it?</p></li><li><p>How do you protect against the dangers of SSH key theft?</p></li></ol><h2><strong>Overview</strong></h2><p>As SSH has been around for a long time, there are some common tools and concepts that can somewhat deal with these concerns, but they can be very complicated and a huge overhead to manage. Some of the key concerns are -</p><ol><li><p>SSH port on a target VM can be kept secured without opening it to the internet by using Bastion hosts(jump servers), <strong>VPN</strong>(<em>Virtual Private Networks</em>) or a combination of the two. While this reduces the number of open ports, we still need to open up some ports for our VPN or the bastion host itself. Any vulnerabilities in the VPN server or the bastion host can still end up exposing the resources.</p></li><li><p>There are also some tools for this like <strong>Teleport</strong> or Netflix&#8217;s <strong>Bless</strong> which can handle some of these concerns. Many companies are using SSH certificates which tools like Netflix&#8217;s Bless helps make it easy. These tools can also protect us from SSH key theft but are complicated to manage.</p></li><li><p>Linux utilities like &#8220;script&#8221; can log what is happening on the VM if you login with SSH.</p></li></ol><p>To mitigate the concerns and management overhead that comes with SSH and the tools in its ecosystem, we looked for some cloud native modern solutions that would give us easy, secure and auditable access. Some of the requirements and good-to-haves we had are listed below.</p><ol><li><p>Accessing VMs without opening ports within our cloud networks</p></li><li><p>Strong auditing features including session audit log file management.</p></li><li><p>Compatibility with config management tools like <strong>Ansible</strong>.</p></li><li><p>An easy way to segregate our VMs and add contextual information based on the <a href="https://yellow.ai">Yellow.ai</a>&#8217;s region it belongs to.</p></li><li><p>Support accessing VMs in on-premise data centers the same way we connect to cloud based VMs.&nbsp;</p></li></ol><h2><strong>Solution</strong></h2><p>After evaluating various options, we at <a href="https://yellow.ai">Yellow.ai</a>&#8217;s Infra Team ended up going with AWS <strong>SSM</strong>(<em>AWS Systems Manager Agent</em>) which has a lot of the features that we wanted.</p><ul><li><p>As the SSM agent creates an outbound connection to the AWS Systems Manager services and receives commands, no inbound ports would have to be opened for us to connect to the VMs. Only outgoing traffic would have to be allowed.&nbsp;</p></li><li><p>Systems manager also supports running SSM agents on VMs in other public clouds and private data centers. This would ensure we can use the same steps to access a VM irrespective of where it is.</p></li><li><p>As all our traffic goes to SSM which AWS ensures is secure, we do not have the overhead of maintaining a centralized server that supports the features we need.</p></li><li><p>The SSM agent logs all the commands that are run on the managed instances and ships them to <strong>S3</strong>(<em>Amazon Simple Storage Service</em>). This ensures that strong auditing is possible while also simplifying the management of the logs.</p></li><li><p>We can centrally ensure that any session has a max duration and automatically a session closes if no traffic is being sent through it.</p></li><li><p>SSM also supports other features allowing custom script execution using SSM Documents. This lets us extend it and use it for running more complex workflows and operations such as running standardized scripts to setup a VM, patch os vulnerabilities and ensure all compliance tasks are automatically getting executed.</p></li><li><p>Segregation of VMs under different regions/deployments could be solved by using tags which is a native way to do it in <strong>AWS</strong>(<em>Amazon Web Services</em>)</p></li></ul><p>To make it easier to use SSM while ensuring relevant information is retained for auditing purposes, we decided to build <strong>CAP</strong> (<em>Central Access Platform</em>) which is a contextual abstraction over AWS Systems Manager&#8217;s Session Manager. CAP gives us programmatic access to execute commands and create browser based interactive sessions to VMs and Kubernetes Clusters. It adds metadata to the managed instances so we know which deployment/environment a VM/Cluster belongs to and creates SSM sessions with user related metadata when an engineer wants to access a VM. Admins and <strong>Infosec</strong> teams can fetch logs for any sessions.&nbsp;It also has <strong>RBAC</strong><em>(Role Based Access Control)</em> which ensures that only Admins can run commands that require sudo access. This lets us change the permissions an engineer has very easily while also helping us with our security and compliance needs.</p><p>There are two ways an engineer can access a VM -</p><ol><li><p>The first is a browser based direct shell that places an engineer within the VM. It is almost instantaneous and great for when an oncall engineer needs to perform some actions. The functionality is limited to shell based commands only and can not be used to access the applications or services running on the VM directly over a TCP/UDP port.</p></li><li><p>The second is a browser based Ubuntu desktop box we call <strong>CAB</strong> <em>(Central Access Box)</em> which can access the VMs. A CAB is useful when an engineer wants to perform some maintenance or operations on multiple VMs which involves additional tooling. A CAB comes with various built in tools like Tableplus, MongoDB Compass, Chrome, Firefox and <em>infractl</em>. <em><strong>infractl</strong></em> is a cli tool which can create sessions and port forward for the users.&nbsp;</p></li></ol><p>An example use case for a CAB is performing Database migrations on db nodes. The engineer can use <em>infractl</em> and port forward to access services on the VM from a CAB so an engineer can use the built in tools.</p><p>A CAB is allowed to access VMs only from the region it was launched for. This also ensures a user can not accidentally copy data from a VM in one Yellow.ai region to another Yellow.ai region.&nbsp;</p><p>To ensure we had a similar experience for Kubernetes, we took inspiration from <strong>EKS</strong>(<em>Amazon Elastic Kubernetes Service<strong>)</strong></em> connector and adopted SSM to work on our clusters. The k8s connector is a pod running on the cluster which together with CAP handles creating a user and assigning the permissions they require based on RBAC. We are now able to connect to our clusters the same way we connect to the VMs. <em><strong>Kubectl</strong></em> is built in this pod and commands can be run like normal. We have the same features of session logging here which is easier to deal with than the kubernetes event logs. A positive side effect of this method of connection is that all the API calls to the cluster control plane are so much faster than using Kubectl locally.</p><p>As part of the provisioning, the Infra Team onboards a resource on CAP. Then when an engineer needs to access a resource, they are able to select the resource they want and connect. A common workflow used for debugging workflow is shown 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_!nF96!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e745ff9-3ee2-454c-8bab-89f3e8880169_891x521.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!nF96!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e745ff9-3ee2-454c-8bab-89f3e8880169_891x521.png 424w, https://substackcdn.com/image/fetch/$s_!nF96!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e745ff9-3ee2-454c-8bab-89f3e8880169_891x521.png 848w, https://substackcdn.com/image/fetch/$s_!nF96!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e745ff9-3ee2-454c-8bab-89f3e8880169_891x521.png 1272w, https://substackcdn.com/image/fetch/$s_!nF96!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e745ff9-3ee2-454c-8bab-89f3e8880169_891x521.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!nF96!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e745ff9-3ee2-454c-8bab-89f3e8880169_891x521.png" width="891" height="521" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1e745ff9-3ee2-454c-8bab-89f3e8880169_891x521.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:521,&quot;width&quot;:891,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!nF96!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e745ff9-3ee2-454c-8bab-89f3e8880169_891x521.png 424w, https://substackcdn.com/image/fetch/$s_!nF96!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e745ff9-3ee2-454c-8bab-89f3e8880169_891x521.png 848w, https://substackcdn.com/image/fetch/$s_!nF96!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e745ff9-3ee2-454c-8bab-89f3e8880169_891x521.png 1272w, https://substackcdn.com/image/fetch/$s_!nF96!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1e745ff9-3ee2-454c-8bab-89f3e8880169_891x521.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>CAP has been in place and getting used for nearly two years now and has helped us many times during incidents and audits.&nbsp;</p><h2><strong>What&#8217;s next?</strong></h2><p>As all these functionalities are consumed through APIs, We have been able to extend these to build an Infra Platform that offers other functionality which are used by various teams at <a href="https://yellow.ai">Yellow.ai</a>. We rely on CAP and SSM APIs to patch VMs, run workflows, and check the current state of a workload on a Kubernetes cluster. We will cover more of these in another blog</p><h4>References:</h4><ul><li><p><a href="https://github.com/Netflix/bless">https://github.com/Netflix/bless</a></p></li><li><p><a href="https://goteleport.com/">https://goteleport.com/</a></p></li><li><p><a href="https://repost.aws/knowledge-center/record-linux-terminal-or-ssh-session">https://repost.aws/knowledge-center/record-linux-terminal-or-ssh-session</a></p></li><li><p><a href="https://docs.aws.amazon.com/systems-manager/latest/userguide/what-is-systems-manager.html">https://docs.aws.amazon.com/systems-manager/latest/userguide/what-is-systems-manager.html</a></p></li></ul>]]></content:encoded></item><item><title><![CDATA[Building accessible chatbots at yellow]]></title><description><![CDATA[Web accessibility, commonly known as a11y, refers to the inclusive practice of designing and developing websites and web applications that can be used by people of all abilities and disabilities.]]></description><link>https://tech.yellow.ai/p/building-accessible-chatbots-at-yellow</link><guid isPermaLink="false">https://tech.yellow.ai/p/building-accessible-chatbots-at-yellow</guid><dc:creator><![CDATA[Adithya N R]]></dc:creator><pubDate>Thu, 25 Jan 2024 10:48:45 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!1X-A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69ca5472-5708-4842-a362-7fde25bc1668_800x512" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!1X-A!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69ca5472-5708-4842-a362-7fde25bc1668_800x512" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1X-A!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69ca5472-5708-4842-a362-7fde25bc1668_800x512 424w, https://substackcdn.com/image/fetch/$s_!1X-A!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69ca5472-5708-4842-a362-7fde25bc1668_800x512 848w, https://substackcdn.com/image/fetch/$s_!1X-A!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69ca5472-5708-4842-a362-7fde25bc1668_800x512 1272w, https://substackcdn.com/image/fetch/$s_!1X-A!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69ca5472-5708-4842-a362-7fde25bc1668_800x512 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1X-A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69ca5472-5708-4842-a362-7fde25bc1668_800x512" width="512" height="512" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/69ca5472-5708-4842-a362-7fde25bc1668_800x512&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:512,&quot;width&quot;:512,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!1X-A!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69ca5472-5708-4842-a362-7fde25bc1668_800x512 424w, https://substackcdn.com/image/fetch/$s_!1X-A!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69ca5472-5708-4842-a362-7fde25bc1668_800x512 848w, https://substackcdn.com/image/fetch/$s_!1X-A!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69ca5472-5708-4842-a362-7fde25bc1668_800x512 1272w, https://substackcdn.com/image/fetch/$s_!1X-A!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F69ca5472-5708-4842-a362-7fde25bc1668_800x512 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">web accessibility</figcaption></figure></div><p><em><strong>Web accessibility</strong></em><strong>, </strong>commonly known as <em><strong>a11y</strong></em>, refers to the inclusive practice of designing and developing websites and web applications that can be used by people of all abilities and disabilities. This includes people with <em><strong>visual</strong></em>, <em><strong>auditory</strong></em>, <em><strong>physical</strong></em>, <em><strong>speech</strong></em>, <em><strong>cognitive</strong></em>, and <em><strong>neurological</strong></em> disabilities.</p><p>Web accessibility is crucial because it ensures everyone has equal access to information and functionality on the Internet.</p><p>One of the most important aspects of web accessibility at <strong><a href="https://yellow.ai">Yellow.ai</a></strong> is ensuring our <strong>chatbots are accessible</strong>. Chatbots have become increasingly popular in recent years, and they are now used by many businesses and organisations to communicate with their customers. However, if chatbots are not designed and developed with accessibility in mind, they can create barriers for people with disabilities. This can lead to frustration and exclusion, resulting in legal issues for businesses and organisations that fail to meet accessibility standards.</p><p>According to the report shared by an accessibility audit firm, in early 2023, we had approximately ~120 accessibility issues on Mac and ~90 issues on Windows. This indicates that our user experience was not up to the mark for differently able users and was not compliant with WCAG guidelines. As a result, we were not a viable option for potential customers in North America and government and educational institutions worldwide.</p><p>In this article, we will explore the challenges we faced and the journey of how we achieved <a href="https://www.w3.org/WAI/standards-guidelines/wcag/">WCAG</a> compliance by improving the a11y of our chatbot interface.</p><h2><strong>Challenges</strong></h2><p>Before we start on how we built an accessible interface, let me walk you through some of the challenges we faced when we first started.</p><ol><li><p><strong>Lack of semantic HTML</strong><br>In <a href="https://yellow.ai/">yellow.ai</a>&#8217;s early days, the primary focus was on swift customer acquisition, so we moved fast, adding features without strict adherence to standard practices. The team, composed largely of &#8220;full-stack&#8221; engineers with limited awareness of these practices, used &#8220;divs&#8221; for everything. The team also overlooked CSS grids or flex boxes and relied on margin, padding, and position workarounds. This meant that the DOM was out of order, and VoiceOver and other accessibility tools failed to parse the content in a user-friendly way.</p></li></ol><div class="captioned-image-container"><figure><a class="image-link image2" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2m4_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dbabf23-919d-42f0-a55e-b63f8292c9d3_253x227.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2m4_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dbabf23-919d-42f0-a55e-b63f8292c9d3_253x227.png 424w, https://substackcdn.com/image/fetch/$s_!2m4_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dbabf23-919d-42f0-a55e-b63f8292c9d3_253x227.png 848w, https://substackcdn.com/image/fetch/$s_!2m4_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dbabf23-919d-42f0-a55e-b63f8292c9d3_253x227.png 1272w, https://substackcdn.com/image/fetch/$s_!2m4_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dbabf23-919d-42f0-a55e-b63f8292c9d3_253x227.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2m4_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dbabf23-919d-42f0-a55e-b63f8292c9d3_253x227.png" width="253" height="227" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7dbabf23-919d-42f0-a55e-b63f8292c9d3_253x227.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:227,&quot;width&quot;:253,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;CleanShot 2023-12-19 at 11.03.33-20231219-053410.png&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="CleanShot 2023-12-19 at 11.03.33-20231219-053410.png" title="CleanShot 2023-12-19 at 11.03.33-20231219-053410.png" srcset="https://substackcdn.com/image/fetch/$s_!2m4_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dbabf23-919d-42f0-a55e-b63f8292c9d3_253x227.png 424w, https://substackcdn.com/image/fetch/$s_!2m4_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dbabf23-919d-42f0-a55e-b63f8292c9d3_253x227.png 848w, https://substackcdn.com/image/fetch/$s_!2m4_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dbabf23-919d-42f0-a55e-b63f8292c9d3_253x227.png 1272w, https://substackcdn.com/image/fetch/$s_!2m4_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7dbabf23-919d-42f0-a55e-b63f8292c9d3_253x227.png 1456w" sizes="100vw" loading="lazy"></picture><div></div></div></a><figcaption class="image-caption">The bot icon button was created using a div without any labels or roles, making it harder for a11y tools to detect the chat widget button.</figcaption></figure></div><ol start="2"><li><p><strong>Not using the platform.</strong><br>We extensively used JavaScript for various tasks in our chatbot, such as calculating the height of the chat window, adjusting the position of certain elements, and manipulating the focus order. Instead of utilizing the tools already provided by HTML and CSS, we relied solely on JavaScript. While this approach initially allowed us to implement features quickly, it ultimately led to several accessibility issues. <br>Our over-reliance on JavaScript meant that the focus order in the chatbot was incorrect. This caused issues for users who relied on keyboard navigation, as they could not navigate the chatbot logically and intuitively. The elements in the DOM were out of order, which caused problems for screen readers and other assistive technologies. As a result, users with disabilities could not access the chatbot's content as easily as they should have been.</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_!71Q8!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2f6e764-18be-4c21-8728-b202e4c1a245_730x423.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!71Q8!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2f6e764-18be-4c21-8728-b202e4c1a245_730x423.png 424w, https://substackcdn.com/image/fetch/$s_!71Q8!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2f6e764-18be-4c21-8728-b202e4c1a245_730x423.png 848w, https://substackcdn.com/image/fetch/$s_!71Q8!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2f6e764-18be-4c21-8728-b202e4c1a245_730x423.png 1272w, https://substackcdn.com/image/fetch/$s_!71Q8!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2f6e764-18be-4c21-8728-b202e4c1a245_730x423.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!71Q8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2f6e764-18be-4c21-8728-b202e4c1a245_730x423.png" width="730" height="423" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b2f6e764-18be-4c21-8728-b202e4c1a245_730x423.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:423,&quot;width&quot;:730,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;0e8794ee-9ba1-4349-9276-f28809c37734.png&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="0e8794ee-9ba1-4349-9276-f28809c37734.png" title="0e8794ee-9ba1-4349-9276-f28809c37734.png" srcset="https://substackcdn.com/image/fetch/$s_!71Q8!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2f6e764-18be-4c21-8728-b202e4c1a245_730x423.png 424w, https://substackcdn.com/image/fetch/$s_!71Q8!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2f6e764-18be-4c21-8728-b202e4c1a245_730x423.png 848w, https://substackcdn.com/image/fetch/$s_!71Q8!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2f6e764-18be-4c21-8728-b202e4c1a245_730x423.png 1272w, https://substackcdn.com/image/fetch/$s_!71Q8!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb2f6e764-18be-4c21-8728-b202e4c1a245_730x423.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">Here&#8217;s how the chat container was structured before. <code>#chatBoxMainContainer</code> represents the container that wraps user and bot messages, and its height had to be calculated using JS every time a different type of component was rendered, causing performance issues. There were also too many unused nodes present in the DOM.</figcaption></figure></div><p></p><ol start="3"><li><p><strong>Customizations</strong><br>Yellow allows customers to personalize the chatbot's appearance and behavior to suit their preferences. However, this customization could affect the contrast ratio, posing a challenge for visually impaired or color-blind users. Customers can also upload images and videos as bot responses, which may not have appropriate alternative texts and closed captions, which poses a challenge for visually impaired users.</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_!aaFd!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca8c867b-a077-4c12-820f-df8524bd5131_736x421.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aaFd!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca8c867b-a077-4c12-820f-df8524bd5131_736x421.png 424w, https://substackcdn.com/image/fetch/$s_!aaFd!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca8c867b-a077-4c12-820f-df8524bd5131_736x421.png 848w, https://substackcdn.com/image/fetch/$s_!aaFd!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca8c867b-a077-4c12-820f-df8524bd5131_736x421.png 1272w, https://substackcdn.com/image/fetch/$s_!aaFd!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca8c867b-a077-4c12-820f-df8524bd5131_736x421.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aaFd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca8c867b-a077-4c12-820f-df8524bd5131_736x421.png" width="736" height="421" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/ca8c867b-a077-4c12-820f-df8524bd5131_736x421.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:421,&quot;width&quot;:736,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;image-20231219-061129.png&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="image-20231219-061129.png" title="image-20231219-061129.png" srcset="https://substackcdn.com/image/fetch/$s_!aaFd!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca8c867b-a077-4c12-820f-df8524bd5131_736x421.png 424w, https://substackcdn.com/image/fetch/$s_!aaFd!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca8c867b-a077-4c12-820f-df8524bd5131_736x421.png 848w, https://substackcdn.com/image/fetch/$s_!aaFd!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca8c867b-a077-4c12-820f-df8524bd5131_736x421.png 1272w, https://substackcdn.com/image/fetch/$s_!aaFd!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fca8c867b-a077-4c12-820f-df8524bd5131_736x421.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">Here&#8217;s an example of a bot that supports a linear gradient as a header background, which causes the text to be barely visible to the user.</figcaption></figure></div><p></p><ol start="4"><li><p><strong>Weak TTS/STT support</strong><br>Our chatbot didn't have reliable Text-to-Speech (TTS) or Speech-to-Text (STT) functionalities at the beginning of our journey. This was a significant barrier for users with visual or physical disabilities, as they could not interact with the chatbot as easily as other users unless they had certain accessibility plugins installed. Users with visual impairments could not hear the responses from the chatbot without TTS, and users with physical disabilities couldn't speak to the chatbot without STT. This limited their ability to fully interact with the chatbot, which was a significant accessibility issue.</p></li></ol><h2><strong>Solution</strong></h2><ol><li><p><strong>Semantic HTML and Using the platform.</strong><br>We resolved 50% of our accessibility issues by refactoring our code to adhere to the semantic HTML guidelines. Using the correct HTML element for each task is important to ensure all built-in accessibility features are readily available. This approach is much better than implementing workarounds using JavaScript.<br><br>We first examined the structure of our DOM nodes and noticed that the order in which they were parsed differed from how they were displayed. Most of our UI layouts were stitched around with divs, with their heights adjusted based on other elements and positions using JavaScript. This caused performance issues and made it impossible for visually impaired users to interact with the widget. For example, the chat banner was originally positioned below the chat conversation container but must be displayed at the top. The quick-reply buttons were placed outside the chat container. To resolve this issue, we reorganized the DOM nodes using Flexbox and grids to ensure that they were in the correct order as they were displayed. By doing so, we also didn&#8217;t need to use JavaScript to adjust the heights of these elements, thereby improving the widget's performance.<br><br>We had a problem with some buttons on our website that were created using <code>&lt;div&gt;</code> instead of the proper button element. This caused issues with the focus order and made it difficult for keyboard users to interact with the widget. Additionally, buttons with icons and no text were not labeled, making it challenging for visually impaired users to know what the button did. To fix this, we added aria labels and titles to these buttons so that screen readers would provide users with information about the button's function. Using attributes like role, aria-label, aria-selected, aria-expanded, etc., we made it easy for users to interact with the widget.</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_!uJXP!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2e5aef4-9750-47c8-a98f-d6b89fde3c69_736x409.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uJXP!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2e5aef4-9750-47c8-a98f-d6b89fde3c69_736x409.png 424w, https://substackcdn.com/image/fetch/$s_!uJXP!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2e5aef4-9750-47c8-a98f-d6b89fde3c69_736x409.png 848w, https://substackcdn.com/image/fetch/$s_!uJXP!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2e5aef4-9750-47c8-a98f-d6b89fde3c69_736x409.png 1272w, https://substackcdn.com/image/fetch/$s_!uJXP!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2e5aef4-9750-47c8-a98f-d6b89fde3c69_736x409.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uJXP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2e5aef4-9750-47c8-a98f-d6b89fde3c69_736x409.png" width="736" height="409" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e2e5aef4-9750-47c8-a98f-d6b89fde3c69_736x409.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:409,&quot;width&quot;:736,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;Group 1.png&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="Group 1.png" title="Group 1.png" srcset="https://substackcdn.com/image/fetch/$s_!uJXP!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2e5aef4-9750-47c8-a98f-d6b89fde3c69_736x409.png 424w, https://substackcdn.com/image/fetch/$s_!uJXP!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2e5aef4-9750-47c8-a98f-d6b89fde3c69_736x409.png 848w, https://substackcdn.com/image/fetch/$s_!uJXP!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2e5aef4-9750-47c8-a98f-d6b89fde3c69_736x409.png 1272w, https://substackcdn.com/image/fetch/$s_!uJXP!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe2e5aef4-9750-47c8-a98f-d6b89fde3c69_736x409.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">With this layout, we no longer need to calculate the height of the chat container every time a new message node is created.</figcaption></figure></div><p></p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;256708bb-0bc4-4033-bea1-d04495ecceff&quot;,&quot;duration&quot;:null}"></div><p>In the above video, the user can now navigate through different buttons and links using the keyboard since we use the right HTML tags for the job</p><p></p><ol start="2"><li><p><strong>Customizations</strong><br>Many customers of <a href="https://yellow.ai/">yellow.ai</a> used custom color schemes for their widget UI, which led to some users being unable to interact with the widget as expected due to their color blindness. To address this issue, we limited the color customizations to the background elements and derived the text color based on these backgrounds and their font sizes. We ensured that the text and icons had the right contrast ratio, with a ratio greater than <code>4.5:1</code> for fonts less than 24px and at least <code>3:1</code> for fonts greater than 24px. This approach ensured all users could interact with the widget without accessibility issues.<br></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_!1smy!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea278b3-58c7-4d0f-b5f5-35f51135c239_450x903.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!1smy!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea278b3-58c7-4d0f-b5f5-35f51135c239_450x903.png 424w, https://substackcdn.com/image/fetch/$s_!1smy!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea278b3-58c7-4d0f-b5f5-35f51135c239_450x903.png 848w, https://substackcdn.com/image/fetch/$s_!1smy!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea278b3-58c7-4d0f-b5f5-35f51135c239_450x903.png 1272w, https://substackcdn.com/image/fetch/$s_!1smy!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea278b3-58c7-4d0f-b5f5-35f51135c239_450x903.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!1smy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea278b3-58c7-4d0f-b5f5-35f51135c239_450x903.png" width="450" height="903" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7ea278b3-58c7-4d0f-b5f5-35f51135c239_450x903.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:903,&quot;width&quot;:450,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;CleanShot 2024-01-03 at 10.42.51@2x-20240103-051304.png&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="CleanShot 2024-01-03 at 10.42.51@2x-20240103-051304.png" title="CleanShot 2024-01-03 at 10.42.51@2x-20240103-051304.png" srcset="https://substackcdn.com/image/fetch/$s_!1smy!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea278b3-58c7-4d0f-b5f5-35f51135c239_450x903.png 424w, https://substackcdn.com/image/fetch/$s_!1smy!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea278b3-58c7-4d0f-b5f5-35f51135c239_450x903.png 848w, https://substackcdn.com/image/fetch/$s_!1smy!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea278b3-58c7-4d0f-b5f5-35f51135c239_450x903.png 1272w, https://substackcdn.com/image/fetch/$s_!1smy!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7ea278b3-58c7-4d0f-b5f5-35f51135c239_450x903.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">The text color inside the chat bubble is automatically generated to be compatible with A &amp; AA level WCAG guidelines.</figcaption></figure></div><p>For images and videos uploaded by customers for bot replies, we provided an option to enter alt texts and captions. Also, we used a default text as a fallback to help the user understand what the media content was about.</p><ol start="3"><li><p><strong>TTS/STT support</strong><br>To ensure that all users, regardless of their accessibility needs, can interact with our widget effectively, we introduced speech-to-text and text-to-speech features. These features are designed to assist users who do not use screen readers or other accessibility technologies but still face difficulties interacting with the site. With speech-to-text, users can speak their messages to the widget, which the widget will then translate into text and send to the bot or chat agent. Similarly, with text-to-speech, the widget will read out the messages on the widget to the user, facilitating interaction. These features enhance the user experience, making our widget more inclusive and accessible.</p></li></ol><p><em>Here&#8217;s TTS in action below -</em></p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;eeb61faa-c6de-4fdf-b57c-b1cccf9afd98&quot;,&quot;duration&quot;:null}"></div><p><em>Here&#8217;s STT and TTS in action together below- </em></p><div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;06f950d8-cf9d-46cd-8daf-b4c543165ef7&quot;,&quot;duration&quot;:null}"></div><p> </p><ol start="4"><li><p><strong>Testing a11y with tools from our accessibility partners</strong><br>Thanks to our accessibility audit partners, we could automate a11y tests to measure how our widget performed regarding accessibility and ease of use. This helped us fix many of our a11y issues, test them, and iterate further on any issues efficiently. Using the axe dev tools and the report provided by a11y engineers at the accessibility firm, we improved the usage of most of our components like quick-replies, product cards, carousels, banners, etc.</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_!ueS2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97b4f37f-3c7c-4130-8675-f4e4b426691b_736x332.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ueS2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97b4f37f-3c7c-4130-8675-f4e4b426691b_736x332.png 424w, https://substackcdn.com/image/fetch/$s_!ueS2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97b4f37f-3c7c-4130-8675-f4e4b426691b_736x332.png 848w, https://substackcdn.com/image/fetch/$s_!ueS2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97b4f37f-3c7c-4130-8675-f4e4b426691b_736x332.png 1272w, https://substackcdn.com/image/fetch/$s_!ueS2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97b4f37f-3c7c-4130-8675-f4e4b426691b_736x332.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ueS2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97b4f37f-3c7c-4130-8675-f4e4b426691b_736x332.png" width="736" height="332" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/97b4f37f-3c7c-4130-8675-f4e4b426691b_736x332.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:332,&quot;width&quot;:736,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;CleanShot 2024-01-03 at 11.12.22@2x-20240103-054231.png&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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="CleanShot 2024-01-03 at 11.12.22@2x-20240103-054231.png" title="CleanShot 2024-01-03 at 11.12.22@2x-20240103-054231.png" srcset="https://substackcdn.com/image/fetch/$s_!ueS2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97b4f37f-3c7c-4130-8675-f4e4b426691b_736x332.png 424w, https://substackcdn.com/image/fetch/$s_!ueS2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97b4f37f-3c7c-4130-8675-f4e4b426691b_736x332.png 848w, https://substackcdn.com/image/fetch/$s_!ueS2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97b4f37f-3c7c-4130-8675-f4e4b426691b_736x332.png 1272w, https://substackcdn.com/image/fetch/$s_!ueS2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97b4f37f-3c7c-4130-8675-f4e4b426691b_736x332.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">Here&#8217;s a screenshot of one of the reports generated while iterating on accessibility issues.</figcaption></figure></div><h2><strong>Outcomes</strong></h2><p>After implementing these changes, we were not only able to significantly enhance the user experience of our chatbot, but we became a feasible choice for clients such as government agencies, educational institutions, and healthcare providers in North America and Europe, where accessibility is a crucial factor for these industries when selecting software. We are now well-positioned to meet their needs.</p><p>The team also learned a lot about building accessible UI and why semantic HTML plays a very important role in building web apps correctly and using the platform as much as possible.</p><h2><strong>What next?</strong></h2><p>Now that we&#8217;ve achieved WCAG compliance, we cannot repeat the same mistakes while we grow further as a product. We use what we learned from this exercise to ensure every new component that&#8217;s built goes through <strong>a11y</strong> tests and provides the best experience possible to all users. Starting with designs, we ensure the contrast ratio follows the guidelines. During development, we ensure keyboard navigation works seamlessly, along with accessibility tools like VoiceOver and others. During QA, we test if the UI is <a href="https://www.w3.org/TR/WCAG21/#perceivable">perceivable</a>, <a href="https://www.w3.org/TR/WCAG21/#operable">operable</a>, <a href="https://www.w3.org/TR/WCAG21/#understandable">understandable</a>, <a href="https://www.w3.org/TR/WCAG21/#robust">robust</a>, and <a href="https://www.w3.org/TR/WCAG21/#conformance">conformant</a>.</p><p>We are committed to providing the best user experience to all our customers and will continue to add more a11y-friendly features in the future.</p>]]></content:encoded></item><item><title><![CDATA[Unveiling the Wonders of VoIP: Introduction (Part-1)]]></title><description><![CDATA[Exploration of Architecture and Protocols]]></description><link>https://tech.yellow.ai/p/unveiling-the-wonders-of-voip-introduction</link><guid isPermaLink="false">https://tech.yellow.ai/p/unveiling-the-wonders-of-voip-introduction</guid><dc:creator><![CDATA[Shailesh Patel]]></dc:creator><pubDate>Wed, 10 Jan 2024 10:59:28 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!aYwD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc77e10d2-fdb5-43de-b4d4-367b248221d4_800x512" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p></p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aYwD!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc77e10d2-fdb5-43de-b4d4-367b248221d4_800x512" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aYwD!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc77e10d2-fdb5-43de-b4d4-367b248221d4_800x512 424w, https://substackcdn.com/image/fetch/$s_!aYwD!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc77e10d2-fdb5-43de-b4d4-367b248221d4_800x512 848w, https://substackcdn.com/image/fetch/$s_!aYwD!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc77e10d2-fdb5-43de-b4d4-367b248221d4_800x512 1272w, https://substackcdn.com/image/fetch/$s_!aYwD!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc77e10d2-fdb5-43de-b4d4-367b248221d4_800x512 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aYwD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc77e10d2-fdb5-43de-b4d4-367b248221d4_800x512" width="512" height="512" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c77e10d2-fdb5-43de-b4d4-367b248221d4_800x512&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:512,&quot;width&quot;:512,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!aYwD!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc77e10d2-fdb5-43de-b4d4-367b248221d4_800x512 424w, https://substackcdn.com/image/fetch/$s_!aYwD!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc77e10d2-fdb5-43de-b4d4-367b248221d4_800x512 848w, https://substackcdn.com/image/fetch/$s_!aYwD!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc77e10d2-fdb5-43de-b4d4-367b248221d4_800x512 1272w, https://substackcdn.com/image/fetch/$s_!aYwD!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc77e10d2-fdb5-43de-b4d4-367b248221d4_800x512 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">VOIP</figcaption></figure></div><p>In the ever-evolving landscape of communication technologies, Voice over Internet Protocol (VoIP) stands out as a transformative force. It has become a widely used alternative to traditional circuit-switched telephone networks due to its cost-effectiveness, flexibility, and the ability to integrate with various multimedia services. This blog delves into the intricate world of VoIP, unraveling its architecture and shedding light on the protocols that power seamless communication over IP-based networks.</p><h3><strong>The Foundation: VoIP Architecture</strong></h3><ul><li><p><strong>Endpoint Devices:</strong> These are the devices used by individuals or businesses to make and receive VoIP calls. Common endpoint devices include smartphones, computers, IP phones, and specialized VoIP hardware.</p></li><li><p><strong>VoIP Software:</strong> VoIP software is responsible for encoding, transmitting, and decoding audio and video data. It is installed on endpoint devices and is necessary for making VoIP calls. Examples of VoIP software include Skype, Zoom, and various softphones.</p></li><li><p><strong>VoIP Servers:</strong> VoIP servers play a crucial role in the VoIP architecture. They manage call setup, routing, and signaling.&nbsp;</p></li></ul><h5>VOIP Servers</h5><p>The key components within VoIP servers include:</p><ul><li><p><strong>SIP (Session Initiation Protocol) Server:</strong> SIP is one of the most common signaling protocols used in VoIP. SIP servers handle call setup, termination, and management.</p></li><li><p><strong>RTP (Real-time Transport Protocol) Server:</strong> RTP is used for transporting audio and video data packets between endpoints. RTP servers help in the efficient and timely delivery of media packets.</p></li><li><p><strong>Media Gateway:</strong> Media gateways are used to interface VoIP networks with traditional PSTN (Public Switched Telephone Network) networks, allowing VoIP calls to connect with regular telephone lines.</p></li><li><p><strong>VoIP Proxy Server:</strong> Proxy servers can be used to improve call quality and security by reducing latency and handling authentication and routing tasks.</p></li></ul><h5><strong>VoIP Protocols</strong></h5><ul><li><p><strong>SIP (Session Initiation Protocol):</strong> SIP is a signaling protocol used for call setup, termination, and management in VoIP networks. It establishes and manages communication sessions between two or more parties.</p></li><li><p><strong>RTP (Real-time Transport Protocol):</strong> RTP is responsible for the transmission and reception of audio and video data packets during a VoIP call. It ensures real-time, low-latency communication.</p></li><li><p><strong>RTCP (RTP Control Protocol):</strong> RTCP works in conjunction with RTP to provide control and monitoring functions for multimedia sessions, including quality of service (QoS) information and statistics.</p></li><li><p><strong>H.323:</strong> Although less common today, H.323 is an older suite of protocols used for multimedia communication, including VoIP. It covers call signaling, control, and media transport.</p></li><li><p><strong>MGCP (Media Gateway Control Protocol):</strong> MGCP is used to control media gateways in VoIP networks. It is typically used in centralized VoIP architectures.</p></li><li><p><strong>H.248/Megaco:</strong> These protocols are used for controlling media gateways in distributed VoIP architectures. They work in conjunction with MGCP.</p></li><li><p><strong>TLS/SSL:</strong> Transport Layer Security (TLS) and Secure Sockets Layer (SSL) are encryption protocols used to secure VoIP communication and protect against eavesdropping and tampering.</p></li><li><p><strong>SDP:</strong> Session Description Protocol, is a text-based protocol used to describe multimedia sessions for the purpose of establishing and managing communication sessions over IP networks. SDP is a key component of various real-time communication protocols and applications, including VoIP (Voice over IP), video conferencing, and multimedia streaming.&nbsp;</p></li></ul><ul><li><p><strong>Codecs:</strong> Codecs (Coder-Decoder) are used to compress and decompress audio and video data for efficient transmission over IP networks. Common codecs include G.711, G.729, and Opus, each with its own trade-offs between bandwidth usage and audio quality.</p><p></p></li></ul><h4>Conclusion</h4><p>VoIP architecture can vary depending on the specific implementation and requirements of the network, but the core components and protocols mentioned above are fundamental to most VoIP systems. VoIP has revolutionized communication by making it more affordable and versatile, enabling a wide range of applications, from simple voice calls to video conferencing and multimedia sharing. </p><p>We will be discussing further on this landscape about <em>Network Components(Part-2)</em> &amp; <em>SIP Trunking(Part-3)</em> in our subsequent blogs. Stay Tuned. <br></p>]]></content:encoded></item><item><title><![CDATA[A Scalable Solution for Mobile App Analytics: The Publisher-Subscriber Model]]></title><description><![CDATA[Introduction]]></description><link>https://tech.yellow.ai/p/a-scalable-solution-for-mobile-app</link><guid isPermaLink="false">https://tech.yellow.ai/p/a-scalable-solution-for-mobile-app</guid><dc:creator><![CDATA[Sankalp Gupta]]></dc:creator><pubDate>Fri, 05 Jan 2024 07:41:08 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!EKcb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2><strong>Introduction</strong></h2><p>In the realm of mobile applications, we often find ourselves grappling with the need to gather valuable insights into user behaviour and application performance. This is particularly true for products that involve real-time interactions, such as Inbox SDK and Partner App. Before delving deeper for Analytics Manager and discussing the solution. Let&#8217;s understand the responsibility of both products first. We will delve deeper into the functionalities and capabilities of these two products, shedding light on their crucial roles.</p><h3><strong>Understanding the Roles and Responsibilities of Inbox SDK and Partner App</strong></h3><p><strong>Inbox SDK</strong></p><p>The Inbox SDK is a robust platform designed to bolster customer support operations, offering a wide array of features that empower businesses to efficiently manage their customer interactions. Let's take a closer look at its core responsibilities:</p><ol><li><p><strong>Overview and Analytics</strong>: The Inbox SDK offers a user-friendly interface for detailed ticket insights, covering live visitor count, chat sessions, queue stats, agent availability, and daily summaries.</p></li></ol><ol start="2"><li><p><strong>Group-Based Analytics</strong>: Inbox SDK enables segmented data analysis, empowering businesses to tailor customer support and engagement strategies for specific groups.</p></li></ol><ol start="3"><li><p><strong>Chat Management</strong>: Inbox SDK provides vital chat tools: segment-based chat lists (e.g., "My Chat," "Open," "Archive"), access to chat details and contacts, actions like transfer, close, reopen, and easy collaboration management within chats.</p></li></ol><ol start="4"><li><p><strong>Public APIs</strong>: Inbox SDK goes beyond UI, offering public APIs for profile tasks. Users manage agent status, make updates, and seamlessly engage with and select bots.</p></li></ol><p><strong>Partner App</strong></p><p>While the inbox SDK is responsible for managing various chat-related operations, the Partner App integrates the Inbox SDK and extends its capabilities, allowing agents to perform partner-specific tasks directly from their mobile devices. Here are its primary responsibilities:</p><ol><li><p>Pre-Login Operations</p></li></ol><ol start="2"><li><p>Profile Interface</p></li></ol><ol start="3"><li><p>Bot Selection and Agent Management</p></li></ol><h2><strong>Problem Statement</strong></h2><p>However, a common challenge developers face is how to log analytics events within their applications effectively. Analytics event loggers like MixPanel and Firebase require the application to initiate events for logging. In our case, this posed a significant challenge: how do we trigger events within our SDKs and ensure that the right events are logged at the right time?</p><h2><strong>Solution</strong></h2><h3><strong>The Analytics Manager</strong></h3><p>At the heart of our approach is the Analytics Manager, a central figure in the orchestration of our analytics framework. This component is responsible for collecting, processing, and dispatching analytics events to the relevant event loggers. Its key features include:</p><ol><li><p><strong>Event Collection</strong>: The Analytics Manager collects events from various sources, such as our Inbox SDK and the Partner App. This ensures that no matter where the event originates, it is captured and processed in a consistent manner.</p></li><li><p><strong>Standardized Logging</strong>: The Manager enforces a standardized logging format for analytics events. This consistency is vital for data quality and the accuracy of subsequent analysis.</p></li><li><p><strong>Event Dispatch</strong>: After processing, the Manager dispatches events to the appropriate event loggers, which may include real-time monitoring and custom analytics modules.</p></li></ol><h3><strong>Publisher-Subscriber Model</strong></h3><p>Our solution is not just about addressing current analytics challenges; it's also designed to accommodate future growth and evolving requirements. This is where the publisher-subscriber pattern comes into play. By incorporating this model into our Analytics Manager, we future-proof our analytics framework in the following ways:</p><ol><li><p><strong>Dynamic Event Handling</strong>: As our software evolves, new events and logging requirements may arise. The publisher-subscriber model allows us to seamlessly integrate these changes. Adding new event types is as simple as introducing a new publisher and subscriber without requiring extensive modifications to the existing infrastructure.</p></li><li><p><strong>Robust Analytics Enhancements</strong>: As our software matures, the need for advanced analytics capabilities becomes more apparent. By utilizing the publisher-subscriber pattern, we build a robust foundation for enhancing our analytics modules, enabling real-time analytics, historical data analysis, and customized analytics solutions tailored to our unique needs.</p></li></ol><p>This approach ensures that analytics events are logged consistently and accurately, regardless of whether they originate from the Inbox SDK or the Partner 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_!EKcb!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!EKcb!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.png 424w, https://substackcdn.com/image/fetch/$s_!EKcb!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.png 848w, https://substackcdn.com/image/fetch/$s_!EKcb!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.png 1272w, https://substackcdn.com/image/fetch/$s_!EKcb!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!EKcb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.png" width="868" height="532" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:532,&quot;width&quot;:868,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:42054,&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_!EKcb!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.png 424w, https://substackcdn.com/image/fetch/$s_!EKcb!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.png 848w, https://substackcdn.com/image/fetch/$s_!EKcb!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.png 1272w, https://substackcdn.com/image/fetch/$s_!EKcb!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2ba0f58c-1d38-4098-9ec5-8cbcd6dfb356_868x532.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><h3>The YellowAnalytics Class</h3><p>At the core of our solution is the creation of a stateless class called <code>YellowAnalytics</code>. This class is responsible for initiating and managing all events related to the SDK. By centralizing event management in this class, we ensure a clean and organized approach to analytics tracking.</p><h3>The <code>trackEvent</code> Function</h3><p>To enable the Partner App to listen to and respond to events generated by the SDK, we've implemented a <code>trackEvent</code> function within the <code>YellowInbox</code> public class. This function acts as a subscriber to events published by the SDK, making it easy for the Partner App to integrate event logging. Here's how it works:</p><p><code>YellowInbox.trackEvent { event, payload in // Call Event loggers to log the new event }</code></p><p>The <code>trackEvent</code> function accepts a closure that takes two parameters: <code>event</code> and <code>payload</code>. These parameters allow the Partner App to access event information and payload data, which can then be passed to the appropriate event loggers like MixPanel or Firebase for logging.</p><h3>Benefits of Our Approach</h3><ol><li><p><strong>Centralized Event Management</strong>: By using the <code>YellowAnalytics</code> class, we centralize event management within our SDKs, making it easier to maintain and extend our analytics capabilities. <code>logEvent</code> function of <code>YellowAnalytics</code> class is responsible for logging events through out the SDK</p></li><li><p><strong>Flexibility for Partner App</strong>: The <code>trackEvent</code> function provides flexibility to the Partner App, allowing it to choose which events to log and how to handle them. This empowers developers to tailor analytics tracking to their specific needs.</p></li><li><p><strong>Consistency in Logging</strong>: With this approach, events are consistently logged, regardless of whether they originate from the Inbox SDK or the Partner App. This ensures that no valuable data is lost, and analytics reports remain accurate.</p></li><li><p><strong>Scalability</strong>: When it comes to the scalability of an evolving SDK, this approach shines by effortlessly incorporating new events and logging demands. The beauty of this mechanism is that it necessitates no changes on the subscriber's end. All that's required is for the publisher to introduce the new events to your application. It's this innate adaptability that fortifies the groundwork for future enhancements in analytics, making it an ideal choice for growth and evolution.</p></li></ol><h2><strong>Conclusion</strong></h2><p>Analytics tracking is a vital aspect of mobile application development, enabling data-driven decision-making and user experience improvements. By implementing an Analytics Manager using a publisher and subscriber pattern, we've overcome the challenge of logging events within our Inbox SDK and Partner App effectively. This approach not only centralises event management but also provides flexibility and scalability for future analytics needs, ensuring that we capture and leverage valuable insights to enhance our mobile Inbox products.</p>]]></content:encoded></item><item><title><![CDATA[Deep Dive into the UI Utility Library: Hawk-eye]]></title><description><![CDATA[Transformative changes have marked Yellow.ai's recent journey in web development.]]></description><link>https://tech.yellow.ai/p/deep-dive-into-the-ui-utility-library</link><guid isPermaLink="false">https://tech.yellow.ai/p/deep-dive-into-the-ui-utility-library</guid><dc:creator><![CDATA[Dhinesh KS]]></dc:creator><pubDate>Mon, 11 Dec 2023 09:20:18 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!I-za!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!I-za!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!I-za!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg 424w, https://substackcdn.com/image/fetch/$s_!I-za!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg 848w, https://substackcdn.com/image/fetch/$s_!I-za!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!I-za!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!I-za!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg" width="1300" height="700" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:700,&quot;width&quot;:1300,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:61321,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/jpeg&quot;,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&quot;topImage&quot;:true,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!I-za!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg 424w, https://substackcdn.com/image/fetch/$s_!I-za!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg 848w, https://substackcdn.com/image/fetch/$s_!I-za!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg 1272w, https://substackcdn.com/image/fetch/$s_!I-za!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9fd70dbb-28c9-4d40-962b-a36a685d504c_1300x700.jpeg 1456w" sizes="100vw" fetchpriority="high"></picture><div class="image-link-expand"><div class="pencraft pc-display-flex pc-gap-8 pc-reset"><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container restack-image"><svg role="img" width="20" height="20" viewBox="0 0 20 20" fill="none" stroke-width="1.5" stroke="var(--color-fg-primary)" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg"><g><title></title><path d="M2.53001 7.81595C3.49179 4.73911 6.43281 2.5 9.91173 2.5C13.1684 2.5 15.9537 4.46214 17.0852 7.23684L17.6179 8.67647M17.6179 8.67647L18.5002 4.26471M17.6179 8.67647L13.6473 6.91176M17.4995 12.1841C16.5378 15.2609 13.5967 17.5 10.1178 17.5C6.86118 17.5 4.07589 15.5379 2.94432 12.7632L2.41165 11.3235M2.41165 11.3235L1.5293 15.7353M2.41165 11.3235L6.38224 13.0882"></path></g></svg></button><button tabindex="0" type="button" class="pencraft pc-reset pencraft icon-container view-image"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-maximize2 lucide-maximize-2"><polyline points="15 3 21 3 21 9"></polyline><polyline points="9 21 3 21 3 15"></polyline><line x1="21" x2="14" y1="3" y2="10"></line><line x1="3" x2="10" y1="21" y2="14"></line></svg></button></div></div></div></a></figure></div><p>Transformative changes have marked <a href="http://yellow.ai/">Yellow.ai</a>'s recent journey in web development. Migration of our cloud app from Monolith to Micro-Frontends with a poly-repo approach, initiated last year, was driven by a dual mission: to reduce build times significantly and to empower individual teams with module-level autonomy.</p><p>However, this was not smooth sailing. Code duplication came up as a major problem. Reusing some basic functionalities like utility functions, constants, state management, and UI elements across different Micro-Frontend was threatening to eat up the benefits we desired. The problem led us to search for a remedy, an instrument that would facilitate the process of code sharing, make it efficient, and make the Micro-Frontend(MFE) architecture more unified. That is where Hawk-eye, our custom-built npm package, gets into the game.</p><p>This blog post will explain how optimizing code sharing through a custom library called Hawk-eye can improve our Micro-Frontend excellence.</p><h3>Understanding the MFE Architecture</h3><p>Evolution in web development has taken place through Micro-frontend architecture as it offers a different path to developing web applications. The basic principle of MFE architecture is to break down large, monolithic applications into self-sufficient components in the same way that microservices work at the backend. Such an innovative approach provides development teams with the independence and adaptability needed to meet the ever-changing needs of web development. Each Micro-Frontend can operate individually and can have a different frontend framework of choice, design standards, and functionality. This process not only simplifies the development procedures but also sets or creates an atmosphere or culture of innovation in which teams may have a choice of the right technologies or tools that are best suited for use with the chosen Micro-Frontend, leading to the ultimate success</p><p>This constitutes a fundamental aspect of our strategy at <a href="http://yellow.ai/">Yellow.ai</a>. We decomposed our cloud application into Micro-Frontends named Channels, the Integration, Engage, and Insights channels with a poly-repo approach (Each MFE will have its repository). These Micro-Frontends are added up into a single container application called web-app, which serves as an entry point to our product suite. They are built in a modular fashion with React as a frontend framework meaning that individual teams can own a separate Micro-Frontend which increases the speed and allows customization based on the requirements.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!PFaW!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F751e9bd7-b443-4894-9d42-e9bdb589c38f_2177x1679.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!PFaW!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F751e9bd7-b443-4894-9d42-e9bdb589c38f_2177x1679.png 424w, https://substackcdn.com/image/fetch/$s_!PFaW!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F751e9bd7-b443-4894-9d42-e9bdb589c38f_2177x1679.png 848w, https://substackcdn.com/image/fetch/$s_!PFaW!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F751e9bd7-b443-4894-9d42-e9bdb589c38f_2177x1679.png 1272w, https://substackcdn.com/image/fetch/$s_!PFaW!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F751e9bd7-b443-4894-9d42-e9bdb589c38f_2177x1679.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!PFaW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F751e9bd7-b443-4894-9d42-e9bdb589c38f_2177x1679.png" width="1456" height="1123" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/751e9bd7-b443-4894-9d42-e9bdb589c38f_2177x1679.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1123,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1011804,&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;: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_!PFaW!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F751e9bd7-b443-4894-9d42-e9bdb589c38f_2177x1679.png 424w, https://substackcdn.com/image/fetch/$s_!PFaW!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F751e9bd7-b443-4894-9d42-e9bdb589c38f_2177x1679.png 848w, https://substackcdn.com/image/fetch/$s_!PFaW!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F751e9bd7-b443-4894-9d42-e9bdb589c38f_2177x1679.png 1272w, https://substackcdn.com/image/fetch/$s_!PFaW!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F751e9bd7-b443-4894-9d42-e9bdb589c38f_2177x1679.png 1456w" sizes="100vw"></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>MFE architecture at Yellow.ai</p><h3>Code duplication challenges</h3><p>Code duplication is one of the common issues in MFE architecture and it affects both development and maintenance in the long-term. Nevertheless, this problem becomes even greater when adopting the poly repo approach.</p><p>When the utility functions, routing, state management, or the user interface components that make up Micro-Frontends if not carefully planned and implemented results in code duplication. This in turn leads to needless reinventions of already available functions, eventually wasting resources. Lastly, all bug fixes as well as modifications involve a well-coordinated concurrent synchronization of different code bases leading to enhanced maintenance challenges. In a nutshell, this code duplication problem poses doubt on the anticipated benefits of MFEs, such as modularity and independence.</p><p>In our Micro-Frontend journey at <a href="https://yellow.ai/">Yellow.ai</a>, adopting the poly repo approach within the MFE architecture resulted in code duplication of shared utilities, constants, and React hooks across various Micro-Frontends. The consequence of observing multiple versions of the same utilities across MFEs reached a point where maintaining consistency became challenging, leading to confusion among developers. Ultimately it ends in disrupting the planned development workflows. Hence, there should be an optimal way to organize the code sharing across the MFEs.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JWUg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a735d3-0f48-4980-823a-0c2938f62f83_2089x1130.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JWUg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a735d3-0f48-4980-823a-0c2938f62f83_2089x1130.png 424w, https://substackcdn.com/image/fetch/$s_!JWUg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a735d3-0f48-4980-823a-0c2938f62f83_2089x1130.png 848w, https://substackcdn.com/image/fetch/$s_!JWUg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a735d3-0f48-4980-823a-0c2938f62f83_2089x1130.png 1272w, https://substackcdn.com/image/fetch/$s_!JWUg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a735d3-0f48-4980-823a-0c2938f62f83_2089x1130.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JWUg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a735d3-0f48-4980-823a-0c2938f62f83_2089x1130.png" width="1456" height="788" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/02a735d3-0f48-4980-823a-0c2938f62f83_2089x1130.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:788,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:682941,&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_!JWUg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a735d3-0f48-4980-823a-0c2938f62f83_2089x1130.png 424w, https://substackcdn.com/image/fetch/$s_!JWUg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a735d3-0f48-4980-823a-0c2938f62f83_2089x1130.png 848w, https://substackcdn.com/image/fetch/$s_!JWUg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a735d3-0f48-4980-823a-0c2938f62f83_2089x1130.png 1272w, https://substackcdn.com/image/fetch/$s_!JWUg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F02a735d3-0f48-4980-823a-0c2938f62f83_2089x1130.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>Code duplication challenges across MFEs at Yellow.ai</p><h3>Ways to Solve the Challenges</h3><p>While the goal is to streamline code sharing within Micro-Frontend architecture, it's crucial to maintain a balance between reusing code effectively and preserving the autonomy and agility of MFE teams. Here, we discuss two strategic approaches to address this challenge in detail</p><ol><li><p><strong>Share Code as a Library</strong></p></li></ol><p>Packing reusable code elements as libraries is one way to prevent code duplication. These shared functionalities are packaged as standalone libraries that can be distributed and consumed as needed, eliminating the need to duplicate common utilities, constants, or React hooks across several Micro-Frontends. Despite the potential diversity in frontend frameworks or technologies used by different Micro-Frontends, the common libraries are designed to be technology-agnostic. They encapsulate functionalities in a way that is independent of the specific tech stack of each Micro-Frontend. Development teams can easily access shared code without sacrificing their autonomy by incorporating these libraries as dependencies. This approach facilitates efficient and consistent maintenance, ensuring that shared functionalities remain consistent, even if individual Micro-Frontends use different technologies.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!og54!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5901d4-d5c6-4141-8f46-069f42cbd494_1672x694.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!og54!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5901d4-d5c6-4141-8f46-069f42cbd494_1672x694.png 424w, https://substackcdn.com/image/fetch/$s_!og54!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5901d4-d5c6-4141-8f46-069f42cbd494_1672x694.png 848w, https://substackcdn.com/image/fetch/$s_!og54!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5901d4-d5c6-4141-8f46-069f42cbd494_1672x694.png 1272w, https://substackcdn.com/image/fetch/$s_!og54!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5901d4-d5c6-4141-8f46-069f42cbd494_1672x694.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!og54!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5901d4-d5c6-4141-8f46-069f42cbd494_1672x694.png" width="1456" height="604" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/cd5901d4-d5c6-4141-8f46-069f42cbd494_1672x694.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:604,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:304978,&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_!og54!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5901d4-d5c6-4141-8f46-069f42cbd494_1672x694.png 424w, https://substackcdn.com/image/fetch/$s_!og54!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5901d4-d5c6-4141-8f46-069f42cbd494_1672x694.png 848w, https://substackcdn.com/image/fetch/$s_!og54!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5901d4-d5c6-4141-8f46-069f42cbd494_1672x694.png 1272w, https://substackcdn.com/image/fetch/$s_!og54!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fcd5901d4-d5c6-4141-8f46-069f42cbd494_1672x694.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>Sharing code as a library</p><ol start="2"><li><p><strong>Share Code as an Individual MFE&nbsp;</strong></p></li></ol><p>Making specialized Micro-Frontends that are only used to host shared code components is another strategy. The purpose of these Micro-Frontends is to act as a central repository for shared functionalities, which other Micro-Frontends can readily access. It's important to note that these specialized Micro-Frontends are designed to be technology-agnostic, ensuring compatibility with various frontend frameworks or technologies used across the application. This method reduces the amount of duplicate code by storing shared code in a specific Micro-Frontend and allowing it to be utilized across the application.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!NTUB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffba5c024-526b-40ca-bdb0-c40014964c71_1546x694.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!NTUB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffba5c024-526b-40ca-bdb0-c40014964c71_1546x694.png 424w, https://substackcdn.com/image/fetch/$s_!NTUB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffba5c024-526b-40ca-bdb0-c40014964c71_1546x694.png 848w, https://substackcdn.com/image/fetch/$s_!NTUB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffba5c024-526b-40ca-bdb0-c40014964c71_1546x694.png 1272w, https://substackcdn.com/image/fetch/$s_!NTUB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffba5c024-526b-40ca-bdb0-c40014964c71_1546x694.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!NTUB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffba5c024-526b-40ca-bdb0-c40014964c71_1546x694.png" width="1456" height="654" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fba5c024-526b-40ca-bdb0-c40014964c71_1546x694.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:654,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:329197,&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_!NTUB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffba5c024-526b-40ca-bdb0-c40014964c71_1546x694.png 424w, https://substackcdn.com/image/fetch/$s_!NTUB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffba5c024-526b-40ca-bdb0-c40014964c71_1546x694.png 848w, https://substackcdn.com/image/fetch/$s_!NTUB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffba5c024-526b-40ca-bdb0-c40014964c71_1546x694.png 1272w, https://substackcdn.com/image/fetch/$s_!NTUB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffba5c024-526b-40ca-bdb0-c40014964c71_1546x694.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>Sharing code as a MFE</p><h3>How We Proceeded</h3><p>In addressing the challenge of code duplication within our MFE architecture at <a href="https://yellow.ai/">Yellow.ai</a>, we implemented a practice where we grouped reusable code into libraries. This choice was made after a thoughtful evaluation of the benefits and considerations of this approach over sharing code as an individual Micro-Frontend. Now, let&#8217;s discuss the particular reasons for our choice.</p><ol><li><p><strong>Maintainability and Version Control:</strong></p></li></ol><p>We obtain a powerful way to preserve and version-control the shared functions by wrapping them up as libraries. For a purpose, libraries allow for independent management and updating of the code components, thereby ensuring that the change that occurred in the shared library is also distributed consistently on all Micro-Frontends. This approach simplifies maintenance efforts, making it possible for an organization to follow up the updates in an easy way.</p><ol start="2"><li><p><strong>Development Workflow Integration:</strong></p></li></ol><p>Custom libraries seamlessly integrate with standard development workflows, enhancing the overall development experience. Including custom libraries in the development process makes it easier to update the shared functionalities.</p><ol start="3"><li><p><strong>Testing and Validation:&nbsp;</strong></p></li></ol><p>Custom libraries provide a convenient environment for testing and validation of shared functionalities. Development teams can test library components independently, ensuring they function as expected. This can streamline the testing process, leading to more robust and reliable shared code.</p><h3>Unveiling Hawk-eye: A Tale of Code Harmony</h3><p>Hawk-eye is the custom library that is crafted as <a href="https://yellow.ai/">Yellow.ai</a>'s utility companion for frontend apps, to combat issues with code duplication among Micro-Frontends. At its core, this "Util Package" is backed with a central repository designed to house common utility functions, constants, and hooks.</p><p><strong>Key Features of Hawk-eye:</strong></p><ol><li><p><strong>Unified Codebase Management:</strong> Orchestrate a unified codebase by consolidating utility functions, constants, and hooks. This ensures a streamlined development process and consistency across Micro-Frontends.</p></li><li><p><strong>Effortless Code Reusability:</strong> Develop a culture of effective code reuse, cut down on redundancy, and create a centralized location for reusable code components to simplify development.</p></li><li><p><strong>Efficient Maintenance Hub:</strong> This "Util Package" serves as a central hub, thereby simplifying the versioning and updates. This ensures that common functionalities evolve uniformly across Micro-Frontends, reducing the risk of inconsistencies.</p></li></ol><h3>Implementation</h3><p><strong>Hawk-eye 1.0 (A Milestone in Code Sharing Excellence)</strong></p><p>Code collaboration was revolutionized by the first version of Hawk-eye 1.0. As <a href="http://yellow.ai/">Yellow.ai</a>&#8217;s point of light, it has dedicated a host for JS utility, constants, and React custom hooks, promoting code sharing across MFEs.</p><p>However, Hawk-eye 1.0 was more than just an introduction &#8211; it promised that development teams would be equipped using unified and simplified practices. We quickly adopted Hawk-eye 1.0 as our utils of choice in Yellow across all MFEs of <a href="http://yellow.ai/">Yellow.ai</a>.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!sBdB!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e2f08e9-5ef3-4426-8290-dfc02dbf1fdd_1694x1128.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!sBdB!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e2f08e9-5ef3-4426-8290-dfc02dbf1fdd_1694x1128.png 424w, https://substackcdn.com/image/fetch/$s_!sBdB!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e2f08e9-5ef3-4426-8290-dfc02dbf1fdd_1694x1128.png 848w, https://substackcdn.com/image/fetch/$s_!sBdB!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e2f08e9-5ef3-4426-8290-dfc02dbf1fdd_1694x1128.png 1272w, https://substackcdn.com/image/fetch/$s_!sBdB!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e2f08e9-5ef3-4426-8290-dfc02dbf1fdd_1694x1128.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!sBdB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e2f08e9-5ef3-4426-8290-dfc02dbf1fdd_1694x1128.png" width="1456" height="970" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2e2f08e9-5ef3-4426-8290-dfc02dbf1fdd_1694x1128.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:970,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:486698,&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_!sBdB!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e2f08e9-5ef3-4426-8290-dfc02dbf1fdd_1694x1128.png 424w, https://substackcdn.com/image/fetch/$s_!sBdB!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e2f08e9-5ef3-4426-8290-dfc02dbf1fdd_1694x1128.png 848w, https://substackcdn.com/image/fetch/$s_!sBdB!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e2f08e9-5ef3-4426-8290-dfc02dbf1fdd_1694x1128.png 1272w, https://substackcdn.com/image/fetch/$s_!sBdB!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2e2f08e9-5ef3-4426-8290-dfc02dbf1fdd_1694x1128.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>Hawk-eye 1.0 Overview</p><p><strong>Challenges and Evolution: A Transformative Journey</strong></p><p>Nevertheless, Hawk-eye 1.0 had some limitations, particularly with React-specific peer dependencies that limited its adaptability for non-React frontend projects. This was the challenge that prompted us to seek a more flexible solution, beyond the domain of frameworks.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2BXi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a45c53-0fae-4353-969b-b844f028bf49_1507x766.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2BXi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a45c53-0fae-4353-969b-b844f028bf49_1507x766.png 424w, https://substackcdn.com/image/fetch/$s_!2BXi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a45c53-0fae-4353-969b-b844f028bf49_1507x766.png 848w, https://substackcdn.com/image/fetch/$s_!2BXi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a45c53-0fae-4353-969b-b844f028bf49_1507x766.png 1272w, https://substackcdn.com/image/fetch/$s_!2BXi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a45c53-0fae-4353-969b-b844f028bf49_1507x766.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2BXi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a45c53-0fae-4353-969b-b844f028bf49_1507x766.png" width="1456" height="740" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/09a45c53-0fae-4353-969b-b844f028bf49_1507x766.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:740,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:724143,&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_!2BXi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a45c53-0fae-4353-969b-b844f028bf49_1507x766.png 424w, https://substackcdn.com/image/fetch/$s_!2BXi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a45c53-0fae-4353-969b-b844f028bf49_1507x766.png 848w, https://substackcdn.com/image/fetch/$s_!2BXi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a45c53-0fae-4353-969b-b844f028bf49_1507x766.png 1272w, https://substackcdn.com/image/fetch/$s_!2BXi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F09a45c53-0fae-4353-969b-b844f028bf49_1507x766.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>Hawk-eye 1.0 Challenges</p><p>It should be noted, however, that this was the turning point in the way we approached Hawk-eye. The pursuit for inclusion sparked an architectural shift in Hawk-eye, Which is dividing the package into two separate bundles backed with a mono-repo. This marked an important milestone in Hawk-eye&#8217;s journey towards greater adaptability and acceptance.</p><p><strong>Hawk-eye 2.0: (Elevating Code Collaboration Mastery)</strong></p><p>Hawk-eye 2.0 represents a deliberate step forward in our journey toward mastering effective code collaboration, that builds upon the foundation set by Hawk-eye 1.0. It's not just an update, either. Rather, it is a strategic evolution that addresses the issues raised by Hawk-eye 1.0, embracing a collaboration model that improves our shared coding while also aiming for increased modularity and adaptability.</p><p><strong>Key Enhancements:</strong>&nbsp;</p><ol><li><p><strong>Distinct Packages for Precise Solutions</strong></p></li></ol><p>Hawk-eye 2.0 divides itself into two distinct packages.</p><ul><li><p><strong>"Hawk-eye-core"</strong>: A powerhouse for JavaScript utilities, ensuring a robust foundation for common functionalities.</p></li><li><p><strong>"Hawk-eye-react"</strong>: Dedicated to React-specific custom hooks and utilities</p></li></ul><p>This enforces a better separation of concerns, enhancing modularity and ensuring a more tailored approach to code sharing. The result is that the packages are versatile enough to use in both react and non-react frontend applications.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!dxk_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b77b46a-425d-4f8d-a7d4-9469776b4619_2819x766.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!dxk_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b77b46a-425d-4f8d-a7d4-9469776b4619_2819x766.png 424w, https://substackcdn.com/image/fetch/$s_!dxk_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b77b46a-425d-4f8d-a7d4-9469776b4619_2819x766.png 848w, https://substackcdn.com/image/fetch/$s_!dxk_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b77b46a-425d-4f8d-a7d4-9469776b4619_2819x766.png 1272w, https://substackcdn.com/image/fetch/$s_!dxk_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b77b46a-425d-4f8d-a7d4-9469776b4619_2819x766.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!dxk_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b77b46a-425d-4f8d-a7d4-9469776b4619_2819x766.png" width="1456" height="396" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4b77b46a-425d-4f8d-a7d4-9469776b4619_2819x766.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:396,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:973078,&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_!dxk_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b77b46a-425d-4f8d-a7d4-9469776b4619_2819x766.png 424w, https://substackcdn.com/image/fetch/$s_!dxk_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b77b46a-425d-4f8d-a7d4-9469776b4619_2819x766.png 848w, https://substackcdn.com/image/fetch/$s_!dxk_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b77b46a-425d-4f8d-a7d4-9469776b4619_2819x766.png 1272w, https://substackcdn.com/image/fetch/$s_!dxk_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b77b46a-425d-4f8d-a7d4-9469776b4619_2819x766.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>Distinct Hawk-eye Packages</p><ol start="2"><li><p><strong>Monorepo adoption</strong></p></li></ol><p>A crucial decision in Hawk-eye 2.0 is the adoption of a mono-repo structure over poly-repo. Monorepo helps in simplification of the development process, code sharing between packages, and collaborative development for packages. This selection allows smooth code sharing between <strong>&#8220;hawk-eye-core&#8221;</strong> and <strong>&#8220;hawk-eye-react&#8221;</strong>, creating a unified environment.</p><p><strong>Monorepo with Lerna:</strong></p><p>There are several monorepo tools available in the landscape including Nx, Lerna, Turborep, etc., which have distinct merits. However, we went with Lerna because of the following reasons</p><ul><li><p><strong>Tailored task pipeline with Nx: </strong><br>A tailored task pipeline that aligned Lerna with Nx was effective in running the scripts in a controlled manner. This is even more true in the case of Hawk-Eye where the build order matters meaning hawk-eye-core has to run before hawk-eye-react because core is a dependency in the react project. This intricate control ensures that our development workflow is productive and predictable.</p></li><li><p><strong>Flexibility in Dependency Management and Structure:</strong><br>Using Lerna&#8217;s flexibility, we created a unified dependency management approach. Consistency in dependency versions is ensured by the global sharing of common packages across React and Core whenever needed. This flexibility allows teams to customize the monorepo of Hawk-Eye based on its specific project needs.</p></li><li><p><strong>Tailored Deployment Solutions:</strong><br>Lerna's adaptability extends to tailored deployment solutions like dependent/ independent versioning of packages. For Hawk-Eye 2.0, this means the freedom to implement custom deployment strategies. Currently, we're utilizing independent versioning for packages, ensuring precise control over version management.</p></li></ul><p>Moreover, Lerna was also among the most popular and commonly used package managers for building as well as publishing multiple JS and TS packages from one repository. Collectively, this brings Lerna best suited with the Hawk-eye monorepo architecture.<br></p><p><strong>Nexus Repository: Streamlining Package Management</strong></p><p>In both versions of Hawk-eye, the Nexus Repository acts as a centralized powerhouse for efficient package management. Serving as a unified hub, Nexus ensures streamlined storage and retrieval, offering developers a centralized location for package management.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!b3J3!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe472188-3e14-4acc-bfb3-09c5183ee2c6_2123x1127.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!b3J3!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe472188-3e14-4acc-bfb3-09c5183ee2c6_2123x1127.png 424w, https://substackcdn.com/image/fetch/$s_!b3J3!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe472188-3e14-4acc-bfb3-09c5183ee2c6_2123x1127.png 848w, https://substackcdn.com/image/fetch/$s_!b3J3!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe472188-3e14-4acc-bfb3-09c5183ee2c6_2123x1127.png 1272w, https://substackcdn.com/image/fetch/$s_!b3J3!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe472188-3e14-4acc-bfb3-09c5183ee2c6_2123x1127.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!b3J3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe472188-3e14-4acc-bfb3-09c5183ee2c6_2123x1127.png" width="1456" height="773" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/be472188-3e14-4acc-bfb3-09c5183ee2c6_2123x1127.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:773,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1067449,&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_!b3J3!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe472188-3e14-4acc-bfb3-09c5183ee2c6_2123x1127.png 424w, https://substackcdn.com/image/fetch/$s_!b3J3!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe472188-3e14-4acc-bfb3-09c5183ee2c6_2123x1127.png 848w, https://substackcdn.com/image/fetch/$s_!b3J3!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe472188-3e14-4acc-bfb3-09c5183ee2c6_2123x1127.png 1272w, https://substackcdn.com/image/fetch/$s_!b3J3!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbe472188-3e14-4acc-bfb3-09c5183ee2c6_2123x1127.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>Hawk-eye 2.0 Overview</p><h3>Learnings from the Hawk-eye Journey</h3><p>Setting out on the Hawk-eye path to Micro-Frontend excellence reveals a wealth of new information and important lessons. A few important conclusions come to light as we examine the nuances of package management, code sharing, and the transition from Hawk-eye 1.0 to 2.0.</p><ol><li><p><strong>Strategic Code Sharing:</strong><br>Discover ways of sharing code in MFE architecture and understand the significance of code sharing. The way Hawk-eye's packaging and modular methods changed how we handle shared components in Micro-Frontends, making things simpler and better.</p></li><li><p><strong>Monorepo Mastery with Lerna:</strong><br>Find the advantages of using a mono-repo setup backed by Lerna. Explore how this strategy enhances package management and version consistency and promotes modularity and collaborations.</p></li><li><p><strong>Centralized Package Management with Nexus:</strong><br>Discover the ways to use Nexus as a centralized repository. See how it enhances the package discoverability, version control, and the singular strategy behind storage and retrieval.</p></li><li><p><strong>Versatility Beyond React:</strong><br>Explore the versatility of Hawk-eye in catering not only to React applications but also seamlessly integrating with non-React projects. Witness how this flexibility opens doors to a wider spectrum of development scenarios.</p></li><li><p><strong>Adapting to Challenges:</strong><br>Understand the challenges encountered in Hawk-eye 1.0 and the improvements made in Hawk-eye 2.0. Going beyond React-specific dependencies, the shift to a more inclusive architecture provides key lessons in tailoring solutions for changing requirements.</p></li></ol><h3>Final Notes</h3><p>Hawk-eye is a game-changing solution for <a href="http://yellow.ai/">Yellow.ai</a>&#8217;s Micro-Frontend architecture, reducing issues such as code duplication and improving development process efficiency. Our journey, which began with Hawk-eye 1.0 and continued with the upgraded Hawk-eye 2.0, is a dedication to improving Micro-Frontend development excellence.</p><p>The adoption of a mono-repo structure, orchestrated by Lerna and Nexus, not only streamlines package management and ensures version consistency but also serves as a beacon for collaborative workflows. Importantly, the modular separation of packages within Hawk-eye enables seamless consumption in both React and non-React applications. Development teams are empowered by this versatility, which provides a unified and flexible solution for Micro-Frontend excellence across various projects and frameworks. Hawk-eye is a testament to innovation, enabling teams to navigate the intricacies of modern web development with confidence and agility. Beyond just a case study; it's a source of inspiration, encouraging a mindset of continuous learning and refinement in Micro-Frontend development practices.</p><h3>References</h3><p><a href="https://levelup.gitconnected.com/micro-frontends-what-why-and-how-bf61f1f0a729">https://levelup.gitconnected.com/micro-frontends-what-why-and-how-bf61f1f0a729</a></p><p><a href="https://www.linkedin.com/pulse/micro-frontends-deep-dive-pros-cons-boudy-de-geer#:~:text=Duplication%20of%20Code%3A%20There%20can,and%20result%20in%20maintenance%20challenges.">Micro Frontends: A Deep Dive into Pros and Cons</a></p><p><a href="https://blog.bitsrc.io/the-dilemma-of-code-reuse-in-microservices-a925ff2b9981">The Dilemma of Code Reuse in Microservices</a></p><p><a href="https://monorepo.tools/">Monorepo Explained</a></p><p><a href="https://medium.com/@Jakeherringbone/you-too-can-love-the-monorepo-d95d1d6fcebe">You too can love the MonoRepo</a></p><p><a href="https://www.toptal.com/front-end/guide-to-monorepos">Guide to Monorepos for Front-end Code | Toptal&#174;</a></p><p><a href="https://lerna.js.org/docs/introduction">Introduction | Lerna</a></p>]]></content:encoded></item><item><title><![CDATA[Yellow.ai's Multi-Region Expansion - Eliminating Single Points of Failure ( Part Two )]]></title><description><![CDATA[In the world of technology and infrastructure management, ensuring robustness and resilience is paramount.]]></description><link>https://tech.yellow.ai/p/yellowais-multi-region-expansion-part-two</link><guid isPermaLink="false">https://tech.yellow.ai/p/yellowais-multi-region-expansion-part-two</guid><dc:creator><![CDATA[Surya Raman]]></dc:creator><pubDate>Wed, 04 Oct 2023 13:26:12 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!HX57!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21002a1d-cd33-4845-9272-ec779f786193_1692x860.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HX57!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21002a1d-cd33-4845-9272-ec779f786193_1692x860.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HX57!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21002a1d-cd33-4845-9272-ec779f786193_1692x860.png 424w, https://substackcdn.com/image/fetch/$s_!HX57!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21002a1d-cd33-4845-9272-ec779f786193_1692x860.png 848w, https://substackcdn.com/image/fetch/$s_!HX57!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21002a1d-cd33-4845-9272-ec779f786193_1692x860.png 1272w, https://substackcdn.com/image/fetch/$s_!HX57!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21002a1d-cd33-4845-9272-ec779f786193_1692x860.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HX57!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21002a1d-cd33-4845-9272-ec779f786193_1692x860.png" width="1456" height="740" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/21002a1d-cd33-4845-9272-ec779f786193_1692x860.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:740,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:101373,&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_!HX57!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21002a1d-cd33-4845-9272-ec779f786193_1692x860.png 424w, https://substackcdn.com/image/fetch/$s_!HX57!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21002a1d-cd33-4845-9272-ec779f786193_1692x860.png 848w, https://substackcdn.com/image/fetch/$s_!HX57!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21002a1d-cd33-4845-9272-ec779f786193_1692x860.png 1272w, https://substackcdn.com/image/fetch/$s_!HX57!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F21002a1d-cd33-4845-9272-ec779f786193_1692x860.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 the world of technology and infrastructure management, ensuring robustness and resilience is paramount. One crucial aspect of achieving this is by eliminating Single Points of Failure (SPOFs). These vulnerabilities can disrupt operations, lead to downtime, and pose significant risks to our business. This blog provides an insider's perspective on how we meticulously identified and eradicated SPOFs, sharing the strategies, insights, and technologies that have strengthened our platform's resilience.</p><p>This blog is the second part of the Multi-Region series from <a href="https://yellow.ai">Yellow.ai</a>. You can read the first part <a href="https://tech.yellow.ai/p/yellowais-multi-region-expansion-part-one">here</a></p><h2>Understanding Primary and Secondary Regions</h2><p>Our primary region functioned as the core metadata hub and was located in India. It included the authentication system with access to essential MySQL databases containing chatbot metadata, user account information, and user roles. The primary region formed the backbone of our operations and was central to our multi-region deployment strategy. Secondary regions complemented the primary region by extending the application's reach to other regions. The secondary regions were geographically dispersed to cater to users outside the primary region. They relied on the primary region for access to the metadata and proxied most of their calls to the primary.&nbsp;</p><p>In the secondary region, not every service proxied requests to the primary region or relied on data from the metadata database. This was limited to a select few core services, with the authentication service being a prominent example. The authentication service worked in a primary-secondary model, where it primarily handled requests by proxying them to the primary region. Additionally, it autonomously processed certain requests before seeking assistance from the primary.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aoQt!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5f6fac4-95e8-416a-b51f-b032a672b2a0_1600x589.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aoQt!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5f6fac4-95e8-416a-b51f-b032a672b2a0_1600x589.png 424w, https://substackcdn.com/image/fetch/$s_!aoQt!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5f6fac4-95e8-416a-b51f-b032a672b2a0_1600x589.png 848w, https://substackcdn.com/image/fetch/$s_!aoQt!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5f6fac4-95e8-416a-b51f-b032a672b2a0_1600x589.png 1272w, https://substackcdn.com/image/fetch/$s_!aoQt!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5f6fac4-95e8-416a-b51f-b032a672b2a0_1600x589.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aoQt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5f6fac4-95e8-416a-b51f-b032a672b2a0_1600x589.png" width="1456" height="536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c5f6fac4-95e8-416a-b51f-b032a672b2a0_1600x589.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:536,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:false,&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_!aoQt!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5f6fac4-95e8-416a-b51f-b032a672b2a0_1600x589.png 424w, https://substackcdn.com/image/fetch/$s_!aoQt!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5f6fac4-95e8-416a-b51f-b032a672b2a0_1600x589.png 848w, https://substackcdn.com/image/fetch/$s_!aoQt!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5f6fac4-95e8-416a-b51f-b032a672b2a0_1600x589.png 1272w, https://substackcdn.com/image/fetch/$s_!aoQt!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc5f6fac4-95e8-416a-b51f-b032a672b2a0_1600x589.png 1456w" sizes="100vw"></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>One such request was user sessions for our platform. When a user authenticated with the primary system, it utilized the metadata database to compute the session object and cached it in Redis. Without this cache, the user was deemed unauthorized. Similarly, when the secondary system attempted to authenticate the user, it initially checked the cache. However, it did not flag the user as unauthorized in the absence of the cache. Instead, it requested session data from the primary system. Depending on whether the primary considered the user authenticated or not, it responded accordingly to the user. Additionally, if the user was deemed authenticated by the primary system, the secondary cached the session for a brief duration. Whenever the primary server purged the session in its Redis instance, it issued commands to the secondary servers to invalidate their caches as well. This gave a clear distinction between regions as primary and secondary.</p><h2>A New Foe: Single Points Of Failure</h2><p>Our first action item post enabling multiple regions was to increase the resilience of the system. We audited every component in the system to find and eliminate single points of failure. Since we had primary and secondary regions, we had to ensure that despite the primary systems going down, none of the secondary systems were affected. We wanted to minimize the blast radius due to any unforeseen problems we could encounter in the primary region. Imagine explaining to a customer in the USA that they cannot use the platform because a remote server in India is temporarily unavailable. Our motivation to eliminate the single point of failure boiled down to building redundancy and resilience across regions.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0EIz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78d0628c-256c-455d-981d-e635770e2cdc_1600x664.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0EIz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78d0628c-256c-455d-981d-e635770e2cdc_1600x664.png 424w, https://substackcdn.com/image/fetch/$s_!0EIz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78d0628c-256c-455d-981d-e635770e2cdc_1600x664.png 848w, https://substackcdn.com/image/fetch/$s_!0EIz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78d0628c-256c-455d-981d-e635770e2cdc_1600x664.png 1272w, https://substackcdn.com/image/fetch/$s_!0EIz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78d0628c-256c-455d-981d-e635770e2cdc_1600x664.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0EIz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78d0628c-256c-455d-981d-e635770e2cdc_1600x664.png" width="1456" height="604" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/78d0628c-256c-455d-981d-e635770e2cdc_1600x664.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:604,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!0EIz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78d0628c-256c-455d-981d-e635770e2cdc_1600x664.png 424w, https://substackcdn.com/image/fetch/$s_!0EIz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78d0628c-256c-455d-981d-e635770e2cdc_1600x664.png 848w, https://substackcdn.com/image/fetch/$s_!0EIz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78d0628c-256c-455d-981d-e635770e2cdc_1600x664.png 1272w, https://substackcdn.com/image/fetch/$s_!0EIz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F78d0628c-256c-455d-981d-e635770e2cdc_1600x664.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>Seamless Failovers</h2><p>Given that the microservices themselves maintain a stateless nature, the key approach was to ensure availability of the shared metadata in more than one region. In the event of an outage in the primary region, the end users would need a seamless switch to a different region that could handle the authentication requests.</p><p>The existing authentication sessions were cached in Redis and new sessions were computed from a MySQL metadata database. If the other region did not access the same data, it would deem the call unauthorized and the users would get logged out in the event of a failover. In essence, two microservices in different regions, both running the same image and connected to identical data sources, were expected to exhibit consistent behavior. With a clear problem statement in place, the subsequent logical step involved breaking it down into smaller concerns to be addressed at the network level, the database level, and the application level. For this, we selected a second region capable of acting as an alternative primary region.</p><h2>Configuring Cloudflare LoadBalancer</h2><p>When the other regions tried to communicate with the primary region, they used the generic domain <em>&#8220;https://cloud.yellow.ai&#8221;</em> instead of a region-specific domain such as <em>&#8220;https://z1.cloud.yellow.ai&#8221;. </em>This allowed us to load balance the requests to any of the primary regions depending on their health. Cloudflare allows the setting up of service health monitoring so we could extend the same health check endpoints used by Kubernetes to Cloudflare and ensure seamless failover. In the event of an untoward service failure, we opted for a simple failover switch since we wanted to avoid introducing a lot of changes to the system at the same time. We ensured that the Load Balancing rules were extensible enough to onboard additional regions as primary.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-pyc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe71a0229-b67d-4f9e-b181-8ccca0544547_1600x1151.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-pyc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe71a0229-b67d-4f9e-b181-8ccca0544547_1600x1151.png 424w, https://substackcdn.com/image/fetch/$s_!-pyc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe71a0229-b67d-4f9e-b181-8ccca0544547_1600x1151.png 848w, https://substackcdn.com/image/fetch/$s_!-pyc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe71a0229-b67d-4f9e-b181-8ccca0544547_1600x1151.png 1272w, https://substackcdn.com/image/fetch/$s_!-pyc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe71a0229-b67d-4f9e-b181-8ccca0544547_1600x1151.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-pyc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe71a0229-b67d-4f9e-b181-8ccca0544547_1600x1151.png" width="1456" height="1047" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e71a0229-b67d-4f9e-b181-8ccca0544547_1600x1151.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1047,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-pyc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe71a0229-b67d-4f9e-b181-8ccca0544547_1600x1151.png 424w, https://substackcdn.com/image/fetch/$s_!-pyc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe71a0229-b67d-4f9e-b181-8ccca0544547_1600x1151.png 848w, https://substackcdn.com/image/fetch/$s_!-pyc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe71a0229-b67d-4f9e-b181-8ccca0544547_1600x1151.png 1272w, https://substackcdn.com/image/fetch/$s_!-pyc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe71a0229-b67d-4f9e-b181-8ccca0544547_1600x1151.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>One side benefit of the setup is that it allowed us to experiment with different Load Balancing strategies such as geo-steering or round-robin so we could determine the best configuration for the lowest latencies in all our regions.</p><h2>Region-to-Region Database Connectivity</h2><p>Once the decision was made to replicate the database between regions, we needed to provide network connectivity. This was straightforward as we had always ensured the CIDR blocks did not overlap between regions. The database subnets were connected with readily available connectivity options provided by our cloud providers that allowed them to communicate with each other, and by extension, replicate the data.</p><h2>Extending the SQL Database</h2><p>The metadata database existed in MySQL, a popular relational database. When we wanted to replicate this database, we considered other relational databases focusing mainly on High Availability and Fault Tolerance. We evaluated MySQL Group Replication, Amazon RDS, and Amazon Aurora. We ruled out RDS immediately because it was not proving to be cost-effective. We found group replication to be a great mechanism and a good fit for us as it worked with the existing setup, but it was a close call. What pushed MySQL GR over the edge was the fact that Aurora could not withstand region-level failures, and was limited to withstanding the loss of Availability Zones within a region. However, Amazon Aurora is a great distributed database and we would consider that for future use cases.</p><p>The main objective of MySQL replication was to make the failovers between regions seamless. This meant the data replication had to be synchronous, and hence, we set the consistency level of the group replication to &#8220;AFTER&#8221;. From the group replication docs,</p><blockquote><p><em>you have a group that has predominantly read-only (RO) data, you want your read-write (RW) transactions to be applied everywhere once they commit, so that subsequent reads are done on up-to-date data that includes your latest writes and you do not pay the synchronization on every RO transaction, but only on RW ones. In this case, you should choose AFTER.</em></p></blockquote><p>Since the system is read-heavy, we could afford the updates to become a bit slower as a trade-off for high availability. It did not change the write latency to anything noticeable, so we got the validation that we had made the right decision.</p><h2>ProxySQL</h2><p>Next up, we wanted the applications to be aware of any topology changes that could happen in MySQL. We evaluated <a href="https://github.com/sysown/proxysql">ProxySQL</a>, <a href="https://dev.mysql.com/doc/mysql-router/8.0/en/">MySQL Router</a>, and <a href="https://mariadb.com/kb/en/maxscale/">MariaDB MaxScale</a>. Based on popular benchmarks, MySQL Router&#8217;s performance was significantly lower than any other proxy tools like MariaDB MaxScale and ProxySQL. This was a deal breaker as we wanted to build a future-proof system. It became clear that the tool required improvements with respect to usability as well as performance. We eliminated MariaDB MaxScale because it needed a commercial license.</p><p>Finally, the community around ProxySQL and the open-source license sealed the decision. ProxySQL ensured the traffic always went to the primary and switched the traffic in the event of any topology change. This meant every application could connect to ProxySQL which would then multiplex the connections to MySQL. It supports read/write split as well should the need arise. Thank you, <a href="https://proxysql.com/blog/author/rene/">Rene Cannao</a>.</p><p>If you are interested in reading more about proxies, <a href="https://youtu.be/mtm-K082d5k">this</a> is a great video that covers most of the relevant MySQL proxies.</p><h2>Redis Sentinel</h2><p>With MySQL replicating out of the way, the next step was to make the same Redis cache available in the alternative primary region. A simple <a href="https://redis.io/docs/management/sentinel/">Redis Sentinel</a> setup was adequate for sharing the authentication data across regions and providing failovers. The sentinels could run on the primary regions as Kubernetes Deployments. They could then communicate with the Redis servers in two different regions and form the shared Cache Layer. The microservices used <em>ioredis</em>, a Redis client capable of understanding sentinels and reconnecting to the Redis server. In case the Sentinels switched the traffic, the use of this library ensured there were minimal disruptions to the end users.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!CuX0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fbec767-9aa4-4fc7-848f-b7770ef26ab8_1600x927.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!CuX0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fbec767-9aa4-4fc7-848f-b7770ef26ab8_1600x927.png 424w, https://substackcdn.com/image/fetch/$s_!CuX0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fbec767-9aa4-4fc7-848f-b7770ef26ab8_1600x927.png 848w, https://substackcdn.com/image/fetch/$s_!CuX0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fbec767-9aa4-4fc7-848f-b7770ef26ab8_1600x927.png 1272w, https://substackcdn.com/image/fetch/$s_!CuX0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fbec767-9aa4-4fc7-848f-b7770ef26ab8_1600x927.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!CuX0!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fbec767-9aa4-4fc7-848f-b7770ef26ab8_1600x927.png" width="1200" height="695.6043956043956" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1fbec767-9aa4-4fc7-848f-b7770ef26ab8_1600x927.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:844,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!CuX0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fbec767-9aa4-4fc7-848f-b7770ef26ab8_1600x927.png 424w, https://substackcdn.com/image/fetch/$s_!CuX0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fbec767-9aa4-4fc7-848f-b7770ef26ab8_1600x927.png 848w, https://substackcdn.com/image/fetch/$s_!CuX0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fbec767-9aa4-4fc7-848f-b7770ef26ab8_1600x927.png 1272w, https://substackcdn.com/image/fetch/$s_!CuX0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1fbec767-9aa4-4fc7-848f-b7770ef26ab8_1600x927.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>Tweaking the Application Layer</h2><p>Each service consuming the metadata database was stateless because the state persisted with the help of Redis and MySQL. This meant any of the regions could become the primary region as long as it had access to the same state. Depending on the configuration loaded, the application could decide whether to act as primary. As a part of the initial setup to enable multiple regions, we also added a proxy middleware in our application to automatically intercept the calls in secondary microservices and send them to the primary service.&nbsp; The proxy middleware had support for sending certain API calls to the local microservice as well, achieving the best of both worlds.<s><br></s><br>In this activity, we introduced support for Sentinel Redis and combed through the applications reading from the metadata database to remove any logic that was written with a single primary region intent. This single primary region programming pattern would cause untoward failures in the event of a failover. Once these patterns were refactored to ensure consistent behavior during failover, we subjected the application to rigorous testing.</p><h2>The Promised Land of No SPOF</h2><p>We did it. We have dismantled SPOFs from our infrastructure, layer by layer. The result is a resilient system that is capable of weathering unforeseen challenges and ensuring uninterrupted service to our users across the globe. As always, we remain cautious about any points of failure we have not realized yet and continue to be on the lookout for them.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!k_uO!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1acff781-b5bb-4c72-84bc-c691a329b701_1600x1059.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!k_uO!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1acff781-b5bb-4c72-84bc-c691a329b701_1600x1059.png 424w, https://substackcdn.com/image/fetch/$s_!k_uO!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1acff781-b5bb-4c72-84bc-c691a329b701_1600x1059.png 848w, https://substackcdn.com/image/fetch/$s_!k_uO!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1acff781-b5bb-4c72-84bc-c691a329b701_1600x1059.png 1272w, https://substackcdn.com/image/fetch/$s_!k_uO!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1acff781-b5bb-4c72-84bc-c691a329b701_1600x1059.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!k_uO!,w_2400,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1acff781-b5bb-4c72-84bc-c691a329b701_1600x1059.png" width="1200" height="794.5054945054945" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1acff781-b5bb-4c72-84bc-c691a329b701_1600x1059.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;large&quot;,&quot;height&quot;:964,&quot;width&quot;:1456,&quot;resizeWidth&quot;:1200,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-large" alt="" srcset="https://substackcdn.com/image/fetch/$s_!k_uO!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1acff781-b5bb-4c72-84bc-c691a329b701_1600x1059.png 424w, https://substackcdn.com/image/fetch/$s_!k_uO!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1acff781-b5bb-4c72-84bc-c691a329b701_1600x1059.png 848w, https://substackcdn.com/image/fetch/$s_!k_uO!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1acff781-b5bb-4c72-84bc-c691a329b701_1600x1059.png 1272w, https://substackcdn.com/image/fetch/$s_!k_uO!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1acff781-b5bb-4c72-84bc-c691a329b701_1600x1059.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>Final Notes</h2><p>At <a href="https://yellow.ai">Yellow.ai</a>, we firmly believe that resilience is not just about withstanding failures but also about thriving in the face of change and uncertainty. Our global commitment to delivering seamless conversational AI experiences drives us to continuously innovate and adapt. As we look to the future, we remain steadfast in our dedication to fortifying our infrastructure, ensuring uninterrupted service, and embracing the opportunities presented by a multi-region, multi-cloud platform.</p>]]></content:encoded></item><item><title><![CDATA[Yellow.ai's Multi-Region Expansion - Charting the Course ( Part One )]]></title><description><![CDATA[In the ever-evolving landscape of conversational AI, Yellow.ai has emerged as a global leader, pioneering autonomous, human-like experiences to foster meaningful brand engagement.]]></description><link>https://tech.yellow.ai/p/yellowais-multi-region-expansion-part-one</link><guid isPermaLink="false">https://tech.yellow.ai/p/yellowais-multi-region-expansion-part-one</guid><dc:creator><![CDATA[Surya Raman]]></dc:creator><pubDate>Wed, 04 Oct 2023 13:25:21 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!ftME!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!ftME!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!ftME!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.png 424w, https://substackcdn.com/image/fetch/$s_!ftME!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.png 848w, https://substackcdn.com/image/fetch/$s_!ftME!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.png 1272w, https://substackcdn.com/image/fetch/$s_!ftME!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!ftME!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.png" width="728" height="370" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:740,&quot;width&quot;:1456,&quot;resizeWidth&quot;:728,&quot;bytes&quot;:97125,&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_!ftME!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.png 424w, https://substackcdn.com/image/fetch/$s_!ftME!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.png 848w, https://substackcdn.com/image/fetch/$s_!ftME!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.png 1272w, https://substackcdn.com/image/fetch/$s_!ftME!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb1ba0c8b-3666-4584-b833-9bdec343ac2f_1692x860.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 the ever-evolving landscape of conversational AI, <a href="https://yellow.ai">Yellow.ai</a> has emerged as a global leader, pioneering autonomous, human-like experiences to foster meaningful brand engagement. To further enhance our capabilities, we embarked on a journey towards enabling our platform in multiple regions. This blog delves into the motivations behind this strategic move, our multi-region architecture, the challenges we encountered, what goes into developing software in a multi-region multi-cloud platform, and how this impacts our business.</p><h2>The Motivation Behind Multi-Region Deployments</h2><p>We are committed to delivering exceptional conversational AI experiences worldwide. Multi-region deployment was a strategic imperative driven by several key factors:</p><ul><li><p><strong>Global Reach:</strong> To cater to a global customer base, we needed infrastructure closer to end-users, reducing latency, and improving response times</p></li><li><p><strong>Scalability</strong>: Multi-region deployment allows us to efficiently scale our infrastructure to meet the growing demands of our global user base, ensuring that we can accommodate the individual needs of each region.</p></li><li><p><strong>Data Privacy and Compliance</strong>: Compliance with diverse data privacy regulations necessitated data localization in specific regions</p></li></ul><h2>The Pledge: Preparing For Multi-Region</h2><div class="pullquote"><p><em>&#8220;Every great magic trick consists of three parts or acts. The first part is called "The Pledge". The magician shows you something ordinary: a deck of cards, a bird, or a man. He shows you this object. Perhaps he asks you to inspect it to see if it is indeed real, unaltered, normal. But of course... it probably isn't. &#8221;</em></p><p><em>&#8213; Christopher Priest, The Prestige</em></p></div><h3>Pre Multi-Region Days</h3><p>Initially, the <a href="https://yellow.ai">Yellow.ai</a> platform was constructed primarily for a single region. As a result, all the microservices were structured around this mindset. Let&#8217;s take a look at the architecture of the system running in a single region.&nbsp;</p><p>The end users can communicate with us through the platform URLs or external channel sources. The traffic arrives at a public Load Balancer and then pours into our Load Balancer - HAProxy. HAProxy helps to route the traffic to different backend systems like Ejabberd (XMPP) and Kubernetes. From HAProxy, the traffic flows to Nginx, the entry point of the managed Kubernetes cluster. Nginx plays a pivotal role in routing requests to various Kubernetes-registered services, where each service is configured as a route within Nginx following the pattern "/api/service-name". These services connect to the databases running in a different subnet. The bots run in their own namespace and are segregated by their type. They can communicate with the customer&#8217;s systems through an egress controller that has a set of static IPs. This is particularly useful when customers want to allowlist IP addresses that can access their systems.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!8HL-!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a35e76a-c0b6-4f0d-9fc8-fbaffd521b1b_1600x1091.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!8HL-!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a35e76a-c0b6-4f0d-9fc8-fbaffd521b1b_1600x1091.png 424w, https://substackcdn.com/image/fetch/$s_!8HL-!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a35e76a-c0b6-4f0d-9fc8-fbaffd521b1b_1600x1091.png 848w, https://substackcdn.com/image/fetch/$s_!8HL-!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a35e76a-c0b6-4f0d-9fc8-fbaffd521b1b_1600x1091.png 1272w, https://substackcdn.com/image/fetch/$s_!8HL-!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a35e76a-c0b6-4f0d-9fc8-fbaffd521b1b_1600x1091.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!8HL-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a35e76a-c0b6-4f0d-9fc8-fbaffd521b1b_1600x1091.png" width="1456" height="993" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9a35e76a-c0b6-4f0d-9fc8-fbaffd521b1b_1600x1091.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:false,&quot;imageSize&quot;:&quot;normal&quot;,&quot;height&quot;:993,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!8HL-!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a35e76a-c0b6-4f0d-9fc8-fbaffd521b1b_1600x1091.png 424w, https://substackcdn.com/image/fetch/$s_!8HL-!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a35e76a-c0b6-4f0d-9fc8-fbaffd521b1b_1600x1091.png 848w, https://substackcdn.com/image/fetch/$s_!8HL-!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a35e76a-c0b6-4f0d-9fc8-fbaffd521b1b_1600x1091.png 1272w, https://substackcdn.com/image/fetch/$s_!8HL-!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9a35e76a-c0b6-4f0d-9fc8-fbaffd521b1b_1600x1091.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>Replication of this architecture and its transformation into a multi-region compatible system posed its own set of challenges. The need to be cloud-agnostic was considered as popular cloud providers were not available in every region. This need also helped us avoid any vendor lock-ins. Even if a popular cloud provider existed in a region, the following points had to be taken into consideration.</p><ul><li><p><strong>Complexity Management</strong>: Handling increased complexity in network configurations, data synchronization, and monitoring</p></li><li><p><strong>Storage Mechanisms</strong>: Using a cloud-agnostic object-storage interface</p></li><li><p><strong>Cost Optimization</strong>: Selecting the ideal zone in a region with reliability and cost-effectiveness</p></li><li><p><strong>External Channel Webhooks: </strong>Handling messaging channels that do not support conditional webhooks for region-based routing of messages to our platform</p></li></ul><h3>Picking New Cloud Regions</h3><p>We had to pick new cloud regions and ensure they were the right place to serve our target markets. Based on this, we had to evaluate the different regions on their uptime, cost, service availability, proximity to customers, and cloud provider support. In India, we already had our services set up in Mumbai. After carefully evaluating the different options, we decided to go with the following regions as they aligned as closely as possible to the metrics.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wwpG!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a7f7c1-4e4a-4734-a776-ebc8a184c988_1600x1109.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wwpG!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a7f7c1-4e4a-4734-a776-ebc8a184c988_1600x1109.png 424w, https://substackcdn.com/image/fetch/$s_!wwpG!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a7f7c1-4e4a-4734-a776-ebc8a184c988_1600x1109.png 848w, https://substackcdn.com/image/fetch/$s_!wwpG!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a7f7c1-4e4a-4734-a776-ebc8a184c988_1600x1109.png 1272w, https://substackcdn.com/image/fetch/$s_!wwpG!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a7f7c1-4e4a-4734-a776-ebc8a184c988_1600x1109.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wwpG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a7f7c1-4e4a-4734-a776-ebc8a184c988_1600x1109.png" width="1456" height="1009" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e8a7f7c1-4e4a-4734-a776-ebc8a184c988_1600x1109.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1009,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!wwpG!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a7f7c1-4e4a-4734-a776-ebc8a184c988_1600x1109.png 424w, https://substackcdn.com/image/fetch/$s_!wwpG!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a7f7c1-4e4a-4734-a776-ebc8a184c988_1600x1109.png 848w, https://substackcdn.com/image/fetch/$s_!wwpG!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a7f7c1-4e4a-4734-a776-ebc8a184c988_1600x1109.png 1272w, https://substackcdn.com/image/fetch/$s_!wwpG!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8a7f7c1-4e4a-4734-a776-ebc8a184c988_1600x1109.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>The Turn: Adopting Cloud-Agnostic Multi-Region Strategies</h2><div class="pullquote"><p><em>&#8220;The second act is called "The Turn". The magician takes the ordinary something and makes it do something extraordinary. Now you're looking for the secret... but you won't find it, because of course you're not really looking. You don't really want to know. You want to be fooled.&#8221;</em></p><p><em>&#8213; Christopher Priest, The Prestige</em></p></div><p>However, in our case, we were transforming an already extraordinary platform into a new beast altogether. There were several architectural changes required before we could see different regions seamlessly communicate among themselves and with the end users. Let&#8217;s go through how we solved these challenges.</p><h3>The Basics: Cluster Replication</h3><p>We had to replicate the Kubernetes cluster over to the new regions which included creating the cluster, spinning up virtual machines for the databases, adding nodes to the cluster, and configuring subnets. You know how it goes. Once the whole cluster was ready, we moved on to the next problem.</p><h3>Cluster Reachability</h3><p>Up next, we ensured that the regions were reachable through the Internet. The platform&#8217;s front end runs in the primary cluster. Depending on the chatbot selected, the front end would call region-specific URLs that were resolved to a Cloudflare LoadBalancer. Based on the host, Cloudflare would forward the request to the appropriate public LoadBalancer. This solution could be extended to any number of clusters without a problem.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!JdQx!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb14541ed-cf14-4c7b-839b-e83554eaebed_1600x1127.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!JdQx!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb14541ed-cf14-4c7b-839b-e83554eaebed_1600x1127.png 424w, https://substackcdn.com/image/fetch/$s_!JdQx!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb14541ed-cf14-4c7b-839b-e83554eaebed_1600x1127.png 848w, https://substackcdn.com/image/fetch/$s_!JdQx!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb14541ed-cf14-4c7b-839b-e83554eaebed_1600x1127.png 1272w, https://substackcdn.com/image/fetch/$s_!JdQx!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb14541ed-cf14-4c7b-839b-e83554eaebed_1600x1127.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!JdQx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb14541ed-cf14-4c7b-839b-e83554eaebed_1600x1127.png" width="1456" height="1026" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b14541ed-cf14-4c7b-839b-e83554eaebed_1600x1127.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1026,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!JdQx!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb14541ed-cf14-4c7b-839b-e83554eaebed_1600x1127.png 424w, https://substackcdn.com/image/fetch/$s_!JdQx!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb14541ed-cf14-4c7b-839b-e83554eaebed_1600x1127.png 848w, https://substackcdn.com/image/fetch/$s_!JdQx!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb14541ed-cf14-4c7b-839b-e83554eaebed_1600x1127.png 1272w, https://substackcdn.com/image/fetch/$s_!JdQx!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb14541ed-cf14-4c7b-839b-e83554eaebed_1600x1127.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 Cloudflare offered <a href="https://blog.cloudflare.com/advanced-certificate-manager/">Multi-Domain Certificates</a>, it made it easier for us to use the same certificate for all our domains. We added all our domains as <a href="https://en.wikipedia.org/wiki/Subject_Alternative_Name">Subject Alternative Names</a> to the same certificate and reduced the time required to configure certificates for all the regions. For the enthusiasts out there, you can examine the certificate we load on <a href="https://cloud.yellow.ai/">our platform</a> to see this in action.</p><p>Each of the regions was assigned a unique region code. Appending these codes to the base domain results in the calls reaching the region-specific Kubernetes cluster. For example, the URL https://z0.cloud.yellow.ai reaches the India cluster while the URL https://z4.cloud.yellow.ai reaches the USA cluster.</p><ul><li><p>z0 - India</p></li><li><p>z1 - Bahrain</p></li><li><p>z2 - Jakarta</p></li><li><p>z3 - Singapore</p></li><li><p>z4 - USA</p></li><li><p>z5 - Europe</p></li></ul><h3>Extend the Authentication System</h3><p>The decision to extend our authentication system stemmed from a fundamental challenge: the primary system&#8217;s access to a critical MySQL database containing essential chatbot metadata such as names and regions, the user account data, and the user roles. This metadata was indispensable for deploying the <a href="https://yellow.ai">Yellow.ai</a> platform globally. While replicating the entire database across regions wasn't an immediate option, we found a viable solution by extending our application's capabilities.</p><p>To put it into context, here's the issue: the primary authentication system in India possessed the sole access to the MySQL database housing the bot metadata. This data forms the bedrock of our bot deployment process worldwide, enabling us to load bots across the globe seamlessly. So, let's dive into the challenges and the ingenious solution that allowed us to seamlessly make our platform a global system.</p><p>We added support in the authentication system to become region-aware and categorized the system into primary and secondary. The primary would handle all incoming requests by itself and the secondary system would proxy incoming requests to the primary. To keep it simple, if the system was running in India, it operated as the primary, and if not, it operated as the secondary. Initially, this approach worked well. However, we soon realized that the latency of communicating from the West Coast of the United States to India was significantly slower than we expected. To address this, we introduced an allowlist that allowed the secondaries to handle specific APIs with a simple framework.</p><p>The logic behind this framework in the secondaries was straightforward:</p><ul><li><p>Query Local Cache Layer for Authentication Data</p></li><li><p>Return if Cache is present</p></li><li><p>Else, query primary for the data, cache, and respond</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_!MvIS!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d9fc0ba-0c0f-4600-ae5c-20654d5c2f68_1600x589.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!MvIS!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d9fc0ba-0c0f-4600-ae5c-20654d5c2f68_1600x589.png 424w, https://substackcdn.com/image/fetch/$s_!MvIS!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d9fc0ba-0c0f-4600-ae5c-20654d5c2f68_1600x589.png 848w, https://substackcdn.com/image/fetch/$s_!MvIS!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d9fc0ba-0c0f-4600-ae5c-20654d5c2f68_1600x589.png 1272w, https://substackcdn.com/image/fetch/$s_!MvIS!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d9fc0ba-0c0f-4600-ae5c-20654d5c2f68_1600x589.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!MvIS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d9fc0ba-0c0f-4600-ae5c-20654d5c2f68_1600x589.png" width="1456" height="536" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/2d9fc0ba-0c0f-4600-ae5c-20654d5c2f68_1600x589.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:536,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!MvIS!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d9fc0ba-0c0f-4600-ae5c-20654d5c2f68_1600x589.png 424w, https://substackcdn.com/image/fetch/$s_!MvIS!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d9fc0ba-0c0f-4600-ae5c-20654d5c2f68_1600x589.png 848w, https://substackcdn.com/image/fetch/$s_!MvIS!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d9fc0ba-0c0f-4600-ae5c-20654d5c2f68_1600x589.png 1272w, https://substackcdn.com/image/fetch/$s_!MvIS!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F2d9fc0ba-0c0f-4600-ae5c-20654d5c2f68_1600x589.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 class="pullquote"><p><em>&#8203;&#8203;There are only two hard things in Computer Science: cache invalidation and naming things.</em></p><p><em>&#8213; Phil Karlton</em></p></div><p>With this logic in place, we needed a robust cache invalidation mechanism to ensure that whenever data in the metadata database was updated, regions not directly connected to this database would invalidate their cache. To achieve this, whenever the primary system updated the metadata, the secondaries received a call from the primary to delete their cache. To prevent issues related to stale cache in case of any invalidation failure, we populated the cache in the secondaries with a short TTL.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-XGg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b83a5-b19e-48c9-acf1-9ac888421512_1600x634.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-XGg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b83a5-b19e-48c9-acf1-9ac888421512_1600x634.png 424w, https://substackcdn.com/image/fetch/$s_!-XGg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b83a5-b19e-48c9-acf1-9ac888421512_1600x634.png 848w, https://substackcdn.com/image/fetch/$s_!-XGg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b83a5-b19e-48c9-acf1-9ac888421512_1600x634.png 1272w, https://substackcdn.com/image/fetch/$s_!-XGg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b83a5-b19e-48c9-acf1-9ac888421512_1600x634.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-XGg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b83a5-b19e-48c9-acf1-9ac888421512_1600x634.png" width="1456" height="577" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/8a3b83a5-b19e-48c9-acf1-9ac888421512_1600x634.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:577,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!-XGg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b83a5-b19e-48c9-acf1-9ac888421512_1600x634.png 424w, https://substackcdn.com/image/fetch/$s_!-XGg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b83a5-b19e-48c9-acf1-9ac888421512_1600x634.png 848w, https://substackcdn.com/image/fetch/$s_!-XGg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b83a5-b19e-48c9-acf1-9ac888421512_1600x634.png 1272w, https://substackcdn.com/image/fetch/$s_!-XGg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F8a3b83a5-b19e-48c9-acf1-9ac888421512_1600x634.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>Data Compliance</h3><p>We had to be careful with data compliance because of strict regulations, as well as the belief system that made us do everything to protect our customers' data. We built the data flow in a way that the metadata about the customers goes to the India cluster, and the actual data of the customers resides in the databases in the region where their bot is configured to run. We ensured that no data, even accidentally, flowed outside the customer's region.</p><h3>Callback Proxy for External Channels</h3><p>In our journey towards multi-region deployment, we faced a challenge: the immutability of URLs for external channels. We had to work around the limitation of some external channels that could be configured to send data to only a single URL. To address this, we introduced the Callback Proxy. This solution utilizes a proxy server that acts as an intermediary between external channels and our multi-region architecture. When data arrives, the callback proxy's routing logic consults a metadata server to determine the appropriate destination, allowing seamless communication without altering existing channel configurations.</p><h3>Cloud-Agnostic Object Storage</h3><p>Next up, we confronted the task of integrating disparate storage systems inherent to each cloud provider. These unique storage offerings and protocols posed a significant obstacle to seamless interoperability. Our solution emerged in the form of <a href="https://github.com/minio/minio">MinIO</a>, an open-source object storage server. MinIO adeptly bridged these divides, allowing us to harmonize our storage infrastructure, ensuring compatibility and data portability across multiple cloud environments. Since MinIO offers support for the s3 protocol out of the box, the applications do not have to worry about where the data is coming from, and they connect to the server in every deployment in the same way. This strategic adoption empowered us to harness the strengths of each cloud provider while preserving our vendor-agnostic approach.</p><h3>Content Delivery Network ( CDN ) and Caching</h3><p>We went ahead with Cloudflare to cache most of the frontend assets. This ensured the fast loading of assets despite the user&#8217;s location. We also tweaked the build pipelines to purge this cache whenever we built a new version of our frontend app or the chat widget.</p><h2>The Prestige: Multi-Region Goes Live</h2><div class="pullquote"><p><em>&#8220;But you wouldn't clap yet. Because making something disappear isn't enough; you have to bring it back. That's why every magic trick has a third act, the hardest part, the part we call "The Prestige".&#8221;</em></p><p><em>&#8213; Christopher Priest, The Prestige</em></p></div><p>With these points being taken care of and through rigorous manual and automated testing, we released this multi-region capability to production. We patted ourselves on the back and rejoiced at this occasion.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uWI2!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9bfcdde-382a-413a-a21e-28300001efdb_1600x1130.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uWI2!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9bfcdde-382a-413a-a21e-28300001efdb_1600x1130.png 424w, https://substackcdn.com/image/fetch/$s_!uWI2!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9bfcdde-382a-413a-a21e-28300001efdb_1600x1130.png 848w, https://substackcdn.com/image/fetch/$s_!uWI2!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9bfcdde-382a-413a-a21e-28300001efdb_1600x1130.png 1272w, https://substackcdn.com/image/fetch/$s_!uWI2!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9bfcdde-382a-413a-a21e-28300001efdb_1600x1130.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uWI2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9bfcdde-382a-413a-a21e-28300001efdb_1600x1130.png" width="1456" height="1028" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c9bfcdde-382a-413a-a21e-28300001efdb_1600x1130.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1028,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:null,&quot;href&quot;:null,&quot;belowTheFold&quot;:true,&quot;topImage&quot;:false,&quot;internalRedirect&quot;:null,&quot;isProcessing&quot;:false,&quot;align&quot;:null,&quot;offset&quot;:false}" class="sizing-normal" alt="" srcset="https://substackcdn.com/image/fetch/$s_!uWI2!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9bfcdde-382a-413a-a21e-28300001efdb_1600x1130.png 424w, https://substackcdn.com/image/fetch/$s_!uWI2!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9bfcdde-382a-413a-a21e-28300001efdb_1600x1130.png 848w, https://substackcdn.com/image/fetch/$s_!uWI2!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9bfcdde-382a-413a-a21e-28300001efdb_1600x1130.png 1272w, https://substackcdn.com/image/fetch/$s_!uWI2!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc9bfcdde-382a-413a-a21e-28300001efdb_1600x1130.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>However, we understood the importance of not resting on our laurels. This marked the initial phase, and as we know, challenges evolve.</p><h2>Epilogue: Life with a Multi-Region Multi-Cloud Platform</h2><p>Navigating life with such a complex platform requires vigilance and several considerations in the way we program the application, the way we roll out new changes and the way we scale it.</p><h3>Programming Patterns</h3><p>When working with microservices that interact with the metadata database, we have to be careful to not work with a single-region mindset. We should factor in the system design, the different regions available, and the fact that the same code can run in either a primary or secondary region, ergo, the same code can either have access to the metadata database or not.</p><h3>Deployment Strategies</h3><p>The deployment strategy should be decided during the time of initial system design to avoid hiccups during the rollout. We can achieve selective rollout for each region through feature gating, a glorified IF condition at the heart of the code. Essentially, the logic boils down to something like</p><pre><code>IF ( isGateEnabled ) {&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;executeNewCode();
} ELSE {
&nbsp;&nbsp;&nbsp;&nbsp;continueWithOldCode();
}</code></pre><p>While feature gating is a valuable technique, we recognize the need for specialized strategies. Applying techniques like gating may not be universally suitable, particularly when dealing with database schema changes. To proactively address this, we emphasize the importance of considering rollout strategies during the initial design phase. This foresight helps mitigate deployment challenges. Additionally, we strongly discourage the use of different images for the same microservice across regions. This uniformity enables us to swiftly address any region-specific code incompatibilities and execute temporary rollbacks when necessary.</p><h3>Scaling and Cost Management</h3><p>Thanks to our amazing Infrastructure Engineering team, we&#8217;re able to understand the optimal configuration for each microservice running in each region with the help of instrumentation and the limits assigned to the Kubernetes workloads. With this, we adjust the workloads to the appropriate resource limits. HPA is set for each microservice by analyzing past traffic, and load testing the application to determine appropriate thresholds. This setup gives us the flexibility to individually scale each region depending on the anticipated traffic or gradual increase in consumption.&nbsp;</p><h2>Final Notes</h2><p><a href="https://yellow.ai">Yellow.ai</a>'s journey into multi-region deployment represents a pivotal step in our commitment to delivering exceptional conversational AI experiences globally. By understanding the challenges, and implementing a resilient architecture, we have fortified our position as a leader in the industry. This strategic move not only benefits our customers but also sets the stage for continued innovation and growth in the world of conversational AI.</p><p>This blog is the first part of a two-part series on multi-region deployments from <a href="https://yellow.ai">Yellow.ai</a>. In our next article, we'll delve into a critical issue: <a href="https://tech.yellow.ai/p/yellowais-multi-region-expansion-part-two">Eliminating Single Points of Failure</a>. </p>]]></content:encoded></item><item><title><![CDATA[Frontend API Instrumentation: A Deep Dive into User-Centric Monitoring]]></title><description><![CDATA[Decoding Frontend API Instrumentation: What It Is and Why It Matters]]></description><link>https://tech.yellow.ai/p/frontend-api-instrumentation-a-deep</link><guid isPermaLink="false">https://tech.yellow.ai/p/frontend-api-instrumentation-a-deep</guid><dc:creator><![CDATA[Anik Das]]></dc:creator><pubDate>Mon, 25 Sep 2023 07:30:30 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!Qybz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Qybz!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Qybz!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.png 424w, https://substackcdn.com/image/fetch/$s_!Qybz!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.png 848w, https://substackcdn.com/image/fetch/$s_!Qybz!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.png 1272w, https://substackcdn.com/image/fetch/$s_!Qybz!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Qybz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.png" width="1100" height="520" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:520,&quot;width&quot;:1100,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:53597,&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_!Qybz!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.png 424w, https://substackcdn.com/image/fetch/$s_!Qybz!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.png 848w, https://substackcdn.com/image/fetch/$s_!Qybz!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.png 1272w, https://substackcdn.com/image/fetch/$s_!Qybz!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3461f8ab-fefe-4e37-a380-43fda6bacdb7_1100x520.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 today's digital age, the performance and reliability of web applications play a pivotal role in ensuring a seamless user experience. As developers and operations teams strive to optimize and monitor their applications, there's a growing emphasis on understanding not just the backend mechanics, but also how these applications perform from the user's perspective. Enter the realm of frontend API instrumentation&#8212;a powerful approach to gauging the real-world performance and behavior of APIs as experienced by the end-users.</p><p>While backend monitoring gives us insights into server health, database performance, and internal service interactions, it's only one piece of the puzzle. To truly grasp the user experience, we need to dive into frontend instrumentation, which captures metrics from the client's vantage point. From measuring actual response times seen at the client end to tracking the errors users encounter, frontend API instrumentation provides invaluable data that can shape our optimization strategies.</p><p>In this blog, we'll explore the nuances of frontend API instrumentation, its significance, and how tools like Prometheus and Grafana can be leveraged to visualize these metrics. We will do a technical deep dive of our frontend API monitoring architecture. We'll also discuss the differences between frontend and backend instrumentation, shedding light on why both are essential for a holistic understanding of application performance.</p><h2>Some Background</h2><p>We have a module called Inbox which is used by live agents to respond to end customers. Systems serving live agents generally have a very low tolerance for service disruption, as they are serving live customers. </p><p>Before we implemented our frontend API telemetry solution, when our customers used to report an error, the only data point we had was from our backend monitoring system. The great thing about the backend monitoring system is that it can tell you, in granular detail, what is going on inside our backend services. But as soon as the packet leaves our infrastructure, we lose control of any metrics on how it arrives at the end customer's system. </p><p>Hence, while it might all seem green from our backend monitoring system, unwanted network latency added by our Proxy, Cloud Service Provider, or our customer's ISP remains in our blind spot. In light of that, our team started on a solution to increase our visibility around API monitoring.</p><p>Technical problems aside, not having the API telemetry coverage also caused a lot of operational hazards. A lot of time is wasted in triaging these issues reported by our customers,</p><ul><li><p>A lot of time used to get wasted in triage</p></li><li><p>Customer dissatisfaction </p></li><li><p>Wasted product development bandwidth and focus looking at the wrong areas</p></li></ul><h2>Significance of Frontend API Instrumentation</h2><p>In the intricate web of application development and monitoring, frontend API instrumentation emerges as a beacon of clarity. It's the lens through which developers can view the real-world performance and behavior of their applications from the user's perspective. While backend monitoring offers insights into server operations, it often misses the nuances of user experience, network latency, and client-side processing. Frontend instrumentation fills this gap.</p><p>By focusing on the frontend, we can capture metrics that truly matter to the end-users. For instance, even if a server processes a request swiftly, the user might still experience delays due to network issues or client-side rendering. Only through frontend instrumentation can such discrepancies be identified and addressed.</p><p>Frontend API telemetry can help us with the following:</p><ol><li><p><strong>User-Centric Monitoring:</strong> Frontend instrumentation offers insights directly related to the user experience, ensuring that applications meet user expectations.</p></li><li><p><strong>Identifying Discrepancies:</strong> It helps in pinpointing differences between server-side performance and actual user-perceived performance.</p></li><li><p><strong>Filling the Blind Spots:</strong> With the increasing complexity of web applications, frontend metrics ensure no performance issue goes unnoticed.</p></li><li><p><strong>Network Latency Insights:</strong> Captures the impact of network conditions on application performance, which backend metrics might overlook.</p></li><li><p><strong>Holistic Understanding:</strong> When combined with backend metrics, frontend instrumentation provides a comprehensive view of application health and areas for optimization.</p></li></ol><h2>The architecture of the system</h2><h3>Overview</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!83WY!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee790b7-1644-4c54-acae-06fb363e206e_1174x628.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!83WY!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee790b7-1644-4c54-acae-06fb363e206e_1174x628.png 424w, https://substackcdn.com/image/fetch/$s_!83WY!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee790b7-1644-4c54-acae-06fb363e206e_1174x628.png 848w, https://substackcdn.com/image/fetch/$s_!83WY!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee790b7-1644-4c54-acae-06fb363e206e_1174x628.png 1272w, https://substackcdn.com/image/fetch/$s_!83WY!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee790b7-1644-4c54-acae-06fb363e206e_1174x628.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!83WY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee790b7-1644-4c54-acae-06fb363e206e_1174x628.png" width="1174" height="628" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/5ee790b7-1644-4c54-acae-06fb363e206e_1174x628.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:628,&quot;width&quot;:1174,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:123792,&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_!83WY!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee790b7-1644-4c54-acae-06fb363e206e_1174x628.png 424w, https://substackcdn.com/image/fetch/$s_!83WY!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee790b7-1644-4c54-acae-06fb363e206e_1174x628.png 848w, https://substackcdn.com/image/fetch/$s_!83WY!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee790b7-1644-4c54-acae-06fb363e206e_1174x628.png 1272w, https://substackcdn.com/image/fetch/$s_!83WY!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F5ee790b7-1644-4c54-acae-06fb363e206e_1174x628.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>We have a web application where we allow our users to log in and access different modules of the platform. The frontend telemetry SDK is integrated with our web application. The SDK collects the metric from our web application and reports it to a custom backend metric aggregator. This metric aggregator then exposes a metric API which is scraped by a <a href="https://github.com/prometheus/prometheus">Prometheus</a> instance. We use <a href="https://github.com/grafana/grafana">Grafana</a> to query the data collected by Prometheus. The Grafana stack is also used to set up alerts on the API metrics, and the alerts are then delivered to Slack.</p><h3>Frontend SDK</h3><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Sr8X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F603703cc-a58c-4daa-ad5c-61b8ed8c8225_1990x941.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Sr8X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F603703cc-a58c-4daa-ad5c-61b8ed8c8225_1990x941.png 424w, https://substackcdn.com/image/fetch/$s_!Sr8X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F603703cc-a58c-4daa-ad5c-61b8ed8c8225_1990x941.png 848w, https://substackcdn.com/image/fetch/$s_!Sr8X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F603703cc-a58c-4daa-ad5c-61b8ed8c8225_1990x941.png 1272w, https://substackcdn.com/image/fetch/$s_!Sr8X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F603703cc-a58c-4daa-ad5c-61b8ed8c8225_1990x941.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Sr8X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F603703cc-a58c-4daa-ad5c-61b8ed8c8225_1990x941.png" width="1456" height="688" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/603703cc-a58c-4daa-ad5c-61b8ed8c8225_1990x941.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:688,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:179371,&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_!Sr8X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F603703cc-a58c-4daa-ad5c-61b8ed8c8225_1990x941.png 424w, https://substackcdn.com/image/fetch/$s_!Sr8X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F603703cc-a58c-4daa-ad5c-61b8ed8c8225_1990x941.png 848w, https://substackcdn.com/image/fetch/$s_!Sr8X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F603703cc-a58c-4daa-ad5c-61b8ed8c8225_1990x941.png 1272w, https://substackcdn.com/image/fetch/$s_!Sr8X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F603703cc-a58c-4daa-ad5c-61b8ed8c8225_1990x941.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 actual frontend SDK is bundled as a <a href="https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API">Web Worker</a>. The main web application reports the data to the Web Worker using <code>PostMessage</code>. The SDK is running a custom-built Prometheus client that converts the received event via <code>postMessage</code> to predefined Prometheus metrics. The worker stores the collected metrics in memory and sends them to a backend metric aggregator every 15 seconds. Once the data is relayed to the backend service, the in-memory metric data is flushed out.<br>The main web application interacts with the Web Worker started by the SDK. The underlying framework uses the popular JavaScript library <a href="https://axios-http.com/docs/intro">Axios</a> to make API calls to our backend system. One cool thing about Axios is that it allows us to add request and response <a href="https://axios-http.com/docs/interceptors">interceptors</a>.<br>We added one request interceptor to extract certain metadata from the request header and added the API call start time metadata to the request config. We also added a response interceptor to actually track the latency using the request metadata, and response status code, in case the request failed, collect the error code, etc. This metadata about the request is then posted to a Web Worker.</p><h3>Metric Aggregator</h3><p>The backend metric collector is a simple NodeJS application that receives the metrics data from frontend. The frontend SDK is generic and sends telemetry data for all APIs that are called using Axios. The backend filters the reported metric based on different custom filters. After filtering the metrics, the backend stores the metric in memory. The backend service also aggregates the metric reported from the frontend to avoid wrong data being stored in Prometheus. More about the aggregation will be discussed later in the article. The backend service also exposes an endpoint for Prometheus to scrape. Prometheus scrapes the metric endpoint every 30s. Once Prometheus scrapes the endpoint, the data in memory is flushed.</p><h3>Collected Metrics</h3><p>Histograms are used for all latency-related metrics such as API response time, WebSocket ping latency, and counters for tracking error counts, request counts, etc.<br>Primarily we collect the following metrics</p><ul><li><p><strong>API Response time:</strong> This is one of the key metrics we track to keep track of our end customer experience for our most critical APIs. The metric adds project ID, and API path labels to allow granular data inspection.</p></li></ul><ul><li><p><strong>Error count:</strong> We also track the error counts as a Prometheus counter metric. This allows us to understand what kind of errors our end users are facing. We also have alerts set up for this metric. The error count metric adds project ID, API path, status code, and error type labels to allow detailed investigation.</p></li><li><p><strong>WebSocket ping latency:</strong> As our web app allows real-time communication, we also keep a tab on latency for our real-time messaging servers. This metric is generally a good indicator of any network bottleneck. It also allows us to get a rough understanding of our users' baseline network latency.</p></li><li><p><strong>API call throughput:</strong> This is actually a derived metric from our API response time metric, which also pushes the API call count. This metric allows us to understand the load pattern originating from our users' browsers.</p></li></ul><h2>Dashboards and Alerting</h2><p>We use the Grafana stack for creating beautiful dashboards to present the collected metric data. The dashboards allow us to filter the data by region, Project ID, path, etc.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!UQvr!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1478d55f-11ff-4212-bcb1-e2bfbb55c66c_2802x1224.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!UQvr!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1478d55f-11ff-4212-bcb1-e2bfbb55c66c_2802x1224.png 424w, https://substackcdn.com/image/fetch/$s_!UQvr!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1478d55f-11ff-4212-bcb1-e2bfbb55c66c_2802x1224.png 848w, https://substackcdn.com/image/fetch/$s_!UQvr!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1478d55f-11ff-4212-bcb1-e2bfbb55c66c_2802x1224.png 1272w, https://substackcdn.com/image/fetch/$s_!UQvr!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1478d55f-11ff-4212-bcb1-e2bfbb55c66c_2802x1224.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!UQvr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1478d55f-11ff-4212-bcb1-e2bfbb55c66c_2802x1224.png" width="1456" height="636" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/1478d55f-11ff-4212-bcb1-e2bfbb55c66c_2802x1224.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:636,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:284288,&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_!UQvr!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1478d55f-11ff-4212-bcb1-e2bfbb55c66c_2802x1224.png 424w, https://substackcdn.com/image/fetch/$s_!UQvr!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1478d55f-11ff-4212-bcb1-e2bfbb55c66c_2802x1224.png 848w, https://substackcdn.com/image/fetch/$s_!UQvr!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1478d55f-11ff-4212-bcb1-e2bfbb55c66c_2802x1224.png 1272w, https://substackcdn.com/image/fetch/$s_!UQvr!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F1478d55f-11ff-4212-bcb1-e2bfbb55c66c_2802x1224.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>We also use the Alerting stack provided by Grafana to set alerts for our dashboard panels. The alerts are then channeled to respective Slack channels for our engineers to take corrective actions.</p><h2>Challenges</h2><h3>performance of the web application</h3><ul><li><p><strong>SDK resource footprint:</strong> One of the most important aspects to consider before building the frontend SDK was keeping the resource footprint (CPU and Memory) of the SDK as low as possible. As the SDK runs in a separate Web Worker inherently the execution is isolated for efficient processing</p></li><li><p><strong>User Experience:</strong> Ensure no disruption to the user's experience with the integration of the new SDK.</p></li><li><p><strong>Data Reporting Frequency:</strong> Reports data to the backend every 15 seconds. This is decided based on heuristics keeping in mind that the interval at which the data gets reported is not too large to miss out on data points and, at the same time not too short to create noise. In our experiment, 15 seconds seemed to be right in the sweet spot.</p></li><li><p><strong>Memory Management:</strong> Data collected for metrics is flushed out after each report, allowing GC to clear up the unused memory.</p></li></ul><h3>Adopting Prometheus</h3><p>Prometheus stands out as one of the most valuable databases for storing telemetry data. It's not only well-accepted but also deeply understood by the SRE and developer community. While we initially toyed with the idea of using other time series databases like TimescaleDB or ClickHouse, our choice ultimately settled on Prometheus. <em>This decision was driven by its ease of use and its alignment with the type of metrics we aimed to track</em>.</p><p>However, implementing Prometheus was not as straightforward as it might seem. Those familiar with Prometheus might already sense the challenges we faced. Collecting telemetry data for thousands of users from their browsers running our custom Prometheus client is similar to collecting telemetry data from thousands of ephemeral servers. At its core, Prometheus operates on a pull-based system. This means that instead of pushing data to Prometheus, it's Prometheus that pulls data from its sources. Given the nature of browsers, it's impractical to scrape data directly from clients running in them. This is where our metric aggregator steps in.</p><div class="pullquote"><p>Collecting telemetry data for thousands of users from their browsers running our custom Prometheus client is similar to collecting telemetry data from thousands of ephemeral servers</p></div><p>Browsers are dynamic environments. Users can close tabs, open new ones, or refresh pages at any given moment. Consequently, every time our browser SDK reports data, it starts from scratch, which is really problematic because it can skew the reported data. To address this, our metric aggregator backend plays a crucial role. It keeps track of the data reported by the browser client and, rather than starting afresh, aggregates this new data (for the same set of labels) with previously reported metrics, storing the combined data in memory.</p><h2>Our Learnings</h2><h3>Backend metrics do not tell the full story</h3><p>You only get to know half the story from your backend observability stack. While this can tell you more about what is going on inside the server and what is causing the issue, it cannot possibly tell the impact on user experience caused by a degraded network. The API metrics collected at the front end have allowed us to close the loop, giving us a full spectrum of data to make an informed decision.</p><h3>Isolating the problem</h3><p>With API telemetry data being available from both frontend and backend segregated by project ID and region, we can quickly isolate the problem whether it is caused by our backend or it is an isolated incident only disrupting a certain fraction of our users.</p><h3>Fast support turnaround time</h3><p>With the full spectrum of data being available, our on-call engineers and support team can now look at the frontend telemetry data and work with our customers for a faster resolution to the problem. Previously, a handful amount of time was being spent looking through the various APM and infrastructure dashboards to identify the root cause of the issue.</p><h3>Designing UX keeping latency in mind</h3><p>With this system in place, the team has access to latency data observed by our end customers, which allows the entire product team to craft a solution keeping end-user experience in mind.</p><h2>Way Forward</h2><p>Our vision for the future of frontend telemetry is not just about collecting data, but about harnessing that data to create tangible, positive impacts on user experience.</p><p>Imagine a world where our applications are so attuned to their environment that they can provide visual cues to users the moment network degradation is detected, ensuring transparency and trust. We're committed to refining our frontend SDK, pushing the boundaries of performance to ensure that our telemetry tools are not just observers but active enhancers of the user experience.</p><p>Furthermore, by adopting OpenTelemetry standards, we're looking to elevate our telemetry practices. This move promises better integration, richer visibility, and a seamless bridge between our frontend metrics and the broader ecosystem of application performance monitoring. But we won't stop there. Our ambition extends to diving deeper into the intricacies of frontend performance, capturing a plethora of metrics that will offer us a crystal-clear understanding of the end-user experience.</p><p>The path ahead is filled with challenges, innovations, and opportunities. But with a clear vision and unwavering commitment, we're poised to redefine the standards of frontend telemetry, ensuring that every user interaction is not just monitored but optimized, celebrated, and enhanced.</p><div><hr></div><p></p>]]></content:encoded></item><item><title><![CDATA[Fixing App Localization in Android App Bundles]]></title><description><![CDATA[Having users from different regions and languages and supporting their languages is crucial for the success of mobile applications in today&#8217;s world.]]></description><link>https://tech.yellow.ai/p/fixing-app-localization-in-android</link><guid isPermaLink="false">https://tech.yellow.ai/p/fixing-app-localization-in-android</guid><dc:creator><![CDATA[Vivek Khandelwal]]></dc:creator><pubDate>Wed, 20 Sep 2023 09:30:58 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!SMBa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!SMBa!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!SMBa!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.png 424w, https://substackcdn.com/image/fetch/$s_!SMBa!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.png 848w, https://substackcdn.com/image/fetch/$s_!SMBa!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.png 1272w, https://substackcdn.com/image/fetch/$s_!SMBa!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!SMBa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.png" width="1456" height="974" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:974,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:2086157,&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_!SMBa!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.png 424w, https://substackcdn.com/image/fetch/$s_!SMBa!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.png 848w, https://substackcdn.com/image/fetch/$s_!SMBa!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.png 1272w, https://substackcdn.com/image/fetch/$s_!SMBa!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F97bb1e9f-8527-4128-bb8d-3a4b646093e4_1982x1326.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></p><p>Having users from different regions and languages and supporting their languages is crucial for the success of mobile applications in today&#8217;s world. However, when using app bundles, an optimization process can cause runtime app localization to break. In this article, we will explore the problem in detail and provide a solution.</p><h1><strong>Understanding the Problem</strong></h1><p>App bundles are the publishing format for Google Play, it contains the compiled code, resources, and assets of an application. When a user downloads apk from Google Play, the store delivers the optimized apk for that particular device according to the configuration of that device.</p><p>However, there is an issue with runtime app localization and app bundles. When using app bundles, the optimized apk does not include unnecessary resources and assets that are not needed for the user&#8217;s specific device, resulting in a smaller download size. The problem arises when runtime app localization relies on dynamically loading localized resources or assets that are not included in the optimized APK. Since these resources are not present in the APK, the app may not be able to retrieve and display the appropriate localized content at runtime, leading to errors or missing translations.</p><h1><strong>Solution -1</strong></h1><p>One possible solution to this problem is to specify in the <code>build.gradle</code> file that all resources should be included in the app bundle</p><pre><code>android {
    // ...
    bundle {
        language {
          enableSplit = false
        }
    }
    // ...
}</code></pre><p>This Specifies that the app bundle should not support configuration APKs for language resources. These resources are instead packaged with each base and dynamic feature APK. This ensures that all required localized resources are present in the optimized APK file generated by the app bundle.</p><p>This Solution will result in an increase in the size of the bundle. To fix this we have another optimized solution which is downloading resources on demand using <strong>PlayCore API</strong></p><h1><strong>Solution -2</strong></h1><p>In this solution, we are using <code>SplitInstallManager</code> class. Whenever the user changes the language, we need to check whether the selected language is installed or not and on basis of it we will set language of the app.</p><pre><code>private fun changeLanguage(selectedLangs: String) {
    val splitInstallManager = SplitInstallManagerFactory.create(context)
    val langs: Set&lt;String&gt; = splitInstallManager.installedLanguages
    if (langs.contains(selectedLangs)) {
        //<strong>TODO:</strong> Change Language Here
    } else {
        val installRequestBuilder = SplitInstallRequest.newBuilder()
        installRequestBuilder.addLanguage(Locale.forLanguageTag(languageSelected))
        splitInstallManager.startInstall(installRequestBuilder.build())
        splitInstallManager.registerListener(object : SplitInstallStateUpdatedListener() {
            fun onStateUpdate(splitInstallSessionState: SplitInstallSessionState) {
                if (splitInstallSessionState.status() === SplitInstallSessionStatus.INSTALLED) {
                    //<strong>TODO:</strong> Change Language Here
                }
            }
        })
    }
}</code></pre><p>Next, when a user opens the app we have to install the downloaded languages. which is done in the <code>attchBaseContext()</code> method.</p><pre><code>@Override
protected void attachBaseContext(Context base) {
    super.attachBaseContext(base);
    // It will install all the downloaded langauges into the app
    SplitCompat.install(this); 
  }</code></pre><p><strong>Done!</strong></p><p>For more information, you can check the official documentation</p><p><a href="https://developer.android.com/guide/playcore/feature-delivery/on-demand#lang_resources">Configure on demand delivery | Android Developers</a></p>]]></content:encoded></item><item><title><![CDATA[Exploring Advanced ViewDataBinding Techniques in Android]]></title><description><![CDATA[Imagine building an Android app with a Complex UI that is getting populated from the data model, whenever the data changes or we have to update the data then it will be a very tedious and error-prone task to manually update every view.]]></description><link>https://tech.yellow.ai/p/exploring-advanced-viewdatabinding</link><guid isPermaLink="false">https://tech.yellow.ai/p/exploring-advanced-viewdatabinding</guid><dc:creator><![CDATA[Vivek Khandelwal]]></dc:creator><pubDate>Wed, 20 Sep 2023 09:29:34 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!R6QR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!R6QR!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!R6QR!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.png 424w, https://substackcdn.com/image/fetch/$s_!R6QR!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.png 848w, https://substackcdn.com/image/fetch/$s_!R6QR!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.png 1272w, https://substackcdn.com/image/fetch/$s_!R6QR!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!R6QR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.png" width="1456" height="974" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:974,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:1168669,&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_!R6QR!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.png 424w, https://substackcdn.com/image/fetch/$s_!R6QR!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.png 848w, https://substackcdn.com/image/fetch/$s_!R6QR!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.png 1272w, https://substackcdn.com/image/fetch/$s_!R6QR!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7bdfd0a4-31ea-4bc1-9ab1-88af442b5fdc_1982x1326.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>Imagine building an Android app with a Complex UI that is getting populated from the data model, whenever the data changes or we have to update the data then it will be a very tedious and error-prone task to manually update every view. What if there is a way to do this work in a single line of code, Thanks to the Android team they have provided methods in <code>ViewDataBinding</code> to do this.</p><p>Let&#8217;s understand two methods of ViewDataBinding which will help us in this scenario by taking an example of a Shopping App that displays a list of products that has product names, prices, and availability. Additionally, there is an &#8220;Add to Cart&#8221; button for each product.</p><h1><strong>1. invalidateAll() -</strong></h1><p>We can use the <code>invalidateAll()</code> method when there is a change in the product list such as showing only available products or showing only not available products. In that case, <code>invalidateAll()</code> on the root binding object for the list will ensure that all views in the list are updated accordingly.</p><p><code>binding.invalidateAll()</code></p><p>Instead of manually updating each view one by one, you can simply call <code>invalidateAll()</code> on the binding object.</p><p><strong>Definition</strong>: This Function is used to do the re-evaluation of all the binding expressions and update the associated UI or basically, it is used to refresh the UI</p><h1><strong>2. executePendingBindings() -</strong></h1><p><code>executePendingBindings()</code> can be used when you want to update the &#8220;Add to Cart&#8221; button immediately. In this case, after updating the availability status of the product in the data model, calling <code>executePendingBindings()</code> on the binding object associated with that specific product item&#8217;s layout will execute the pending binding updates, ensuring the button reflects the latest availability state.</p><p><code>binding.executePendingBindings()</code></p><p><strong>Definition</strong>: The <code>executePendingBindings()</code> function is used to immediately update or execute the pending data binding updates. it ensures that all pending updates are applied to the associated UI components.</p><p>While both <code>invalidateAll()</code> and <code>executePendingBindings()</code> are used to update the UI when the underlying data model changes, they serve different purposes and are applied in different scenarios. Here's when you would typically use each method:</p><h2><code>invalidateAll()</code>:</h2><ul><li><p>This method is useful when you need to update multiple views in the layout simultaneously or when you want to ensure a complete refresh of the UI.</p></li><li><p>For example, if you have a data-bound layout with numerous views, and you want to update all of them at once to reflect changes in the data model, you can invoke <code>invalidateAll()</code></p></li></ul><h2><code>executePendingBindings()</code>:</h2><ul><li><p>This method ensures that any pending binding updates for a particular view or views are executed immediately, without waiting for the next layout pass.</p></li><li><p>For example, if you have a specific view that needs to be updated immediately after a change in the data model, you can call <code>executePendingBindings()</code> on that view's binding object to trigger the update.</p></li></ul><p>In summary, use <code>invalidateAll()</code> when you need to update the entire layout or multiple views simultaneously, providing a comprehensive refresh of the UI. On the other hand, use <code>executePendingBindings()</code> when you want to immediately update specific views affected by changes in the data model, ensuring real-time updates.</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tech.yellow.ai/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 Tech @ Yellow AI ! 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>]]></content:encoded></item><item><title><![CDATA[iOS app Internationalization(i18n) using Swift — Part2 ]]></title><description><![CDATA[This article is the continuation of the previous article on iOS app Internationalization. You can view the previous article here. In the last part, we have covered the basics of Internationalization & Localization concepts, starter project structure, and the approach for internationalization by localizing the]]></description><link>https://tech.yellow.ai/p/ios-app-internationalizationi18n-982</link><guid isPermaLink="false">https://tech.yellow.ai/p/ios-app-internationalizationi18n-982</guid><dc:creator><![CDATA[Rohit Kumar]]></dc:creator><pubDate>Wed, 20 Sep 2023 08:12:51 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4304d86c-6482-40f7-9334-115c875c924c_1020x1916.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>This article is the continuation of the previous article on iOS app Internationalization. You can view the previous article <em><a href="https://tech.yellow.ai/p/ios-app-internationalizationi18n">here</a></em>.</p><p>In the last part, we have covered the basics of Internationalization &amp; Localization concepts, <em><a href="https://github.com/rohit-13/InternationalizationDemo/tree/starter-project">starter project</a></em> structure, and the approach for internationalization by localizing the <em>storyboard and </em>localizing strings in the swift code. The previous approach was not so efficient as it was a time consuming and had too much manaul tasks.</p><h2><strong>Live localization via storyboards! What&#8216;s in this new approach?</strong></h2><blockquote><p><em>Let&#8217;s take a scenario, Ram is an iOS developer working on a large and a complex app and now he wants to add i18n support for multiple languages (let&#8217;s say five different languages).<br>Now, instead of localizing the whole storyboard, we will add a </em><code>@IBInspectable</code><strong> </strong>elemnet for each objects(Button, Label, TextField,&#8230;) in storyboard in such a way that we don&#8217;t have to manually localize the text in each object in the storyboard <em>&amp; </em>it should be automatically mamaged by our helper extensions (which we will add in implementation part).<br>Also, we will add a helper to get the translated strings as per the selected language. So, now let&#8217;s jump into the implementation part.</p><p><em>1. Add additional languages support to the app as we do in the last article.<br>Project Navigator &#8594; project name </em><code>InternationalizationDemo</code>&#8594; Info segment &#8594; check the <code>Use Base Internationalization</code> &#8594; click on add <code>+</code> button &#8594;<br>Choose <code>Hindi (hi)</code> &#8594; but don&#8217;t checkmark the storyboards.</p><p><em>2. Add </em><code>Localizable.strings</code> files for both English(base language) &amp; Hindi that will contain all different texts exisiting in storyboards, xib files and swift codes.</p><p><em>3. Create a helper class </em><code>LocalizationHelper</code> that will return the localized string for different texts as per the selected language.</p><p><em>4. Add Localizable Extensions for </em><code>@IBInspectable</code> elements.</p><p><em>5. Add values for </em><code>localizedKey</code> in the attribute inspector for each objects in the storyboard.</p><p><em>6. Localizing strings in the swift code using </em><code>LocalizationHelper</code></p></blockquote><h1><code>Adding the Localizable Strings</code></h1><p>Let&#8217;s add the localize strings files similarly as we do in the last part.</p><p>Select File &#8594; New File &#8594; search for Strings File &#8594; keep the name <strong>Localizable</strong> as default.<br>&#8226; Xcode will generate <code>Localizable.strings</code> file. In the file inspector, you will see <strong>localization </strong>panel. Click localize and select &#8220;Localize&#8221;.<br>&#8226; Again in the file inspector, check <strong>Hindi </strong>in<strong> localization </strong>panel. Xcode will generate two <code>Localizable.strings</code> files for both English and Hindi.</p><p>Let&#8217;s add all the different strings located in the complete project (in storyboards, in xib files, swift codes,&#8230;) firstly for the base language.</p><pre><code>/* 
  Localizable.strings (English)
*/

"sign-in-to-account" = "Sign in to your account";
"enter-email" = "Enter email";
"email" = "Email";
"enter-password" = "Enter password";
"password" = "Password";
"sign-in" = "Sign in";
"sign-up-here" = "Don't have an account. Sign up here";

"back" = "Back";
"back-to-login" = "Back to login";
"create-new-account" = "Create a new account";
"confirm-password" = "Confirm password";
"sign-up" = "Sign up";
"account-already-exists" = "Account already exists.";
"account-created-successfully" = "Account created successfully.";
"invalid-credentials" = "Invalid Credentials";

"welcome-user" = "Welcome %@";
"select-language" = "Select Language";
"done" = "Done";
"error" = "Error";
"ok" = "OK";
"close" = "Close";</code></pre><p>Similarly add the translated strings in Localizable (Hindi).</p><pre><code>
/* 
  Localizable.strings (Hindi)
*/

"sign-in-to-account" = "&#2309;&#2346;&#2344;&#2375; &#2309;&#2325;&#2366;&#2313;&#2306;&#2335; &#2350;&#2375;&#2306; &#2360;&#2366;&#2311;&#2344; &#2311;&#2344; &#2325;&#2352;&#2375;&#2306;";
"enter-email" = "&#2312;&#2350;&#2375;&#2354; &#2342;&#2352;&#2381;&#2332; &#2325;&#2352;&#2375;&#2306;";
"email" = "&#2312;&#2350;&#2375;&#2354;";
"enter-password" = "&#2346;&#2366;&#2360;&#2357;&#2352;&#2381;&#2337; &#2342;&#2352;&#2381;&#2332; &#2325;&#2352;&#2375;&#2306;";
"password" = "&#2346;&#2366;&#2360;&#2357;&#2352;&#2381;&#2337;";
"sign-in" = "&#2360;&#2366;&#2311;&#2344; &#2311;&#2344;";
"sign-up-here" = "&#2325;&#2379;&#2312; &#2326;&#2366;&#2340;&#2366; &#2344;&#2361;&#2368;&#2306; &#2361;&#2376;. &#2351;&#2361;&#2366;&#2306; &#2360;&#2366;&#2311;&#2344; &#2309;&#2346; &#2325;&#2352;&#2375;&#2306;";

"back" = "&#2346;&#2368;&#2331;&#2375;";
"back-to-login" = "&#2354;&#2377;&#2327;&#2367;&#2344; &#2346;&#2352; &#2357;&#2366;&#2346;&#2360; &#2332;&#2366;&#2319;&#2306;";
"create-new-account" = "&#2319;&#2325; &#2344;&#2351;&#2366; &#2326;&#2366;&#2340;&#2366; &#2348;&#2344;&#2366;&#2319;&#2306;";
"confirm-password" = "&#2346;&#2366;&#2360;&#2357;&#2352;&#2381;&#2337; &#2325;&#2368; &#2346;&#2369;&#2359;&#2381;&#2335;&#2367; &#2325;&#2352;&#2375;&#2306;";
"sign-up" = "&#2360;&#2366;&#2311;&#2344; &#2309;&#2346;";
"account-already-exists" = "&#2326;&#2366;&#2340;&#2366; &#2346;&#2361;&#2354;&#2375; &#2360;&#2375; &#2350;&#2380;&#2332;&#2370;&#2342; &#2361;&#2376;&#2404;";
"account-created-successfully" = "&#2326;&#2366;&#2340;&#2366; &#2360;&#2347;&#2354;&#2340;&#2366;&#2346;&#2370;&#2352;&#2381;&#2357;&#2325; &#2348;&#2344;&#2366;&#2351;&#2366; &#2327;&#2351;&#2366;.";
"invalid-credentials" = "&#2309;&#2357;&#2376;&#2343; &#2346;&#2381;&#2352;&#2340;&#2381;&#2351;&#2351; &#2346;&#2340;&#2381;&#2352;";

"welcome-user" = "&#2360;&#2381;&#2357;&#2366;&#2327;&#2340; &#2361;&#2376; %@";
"select-language" = "&#2349;&#2366;&#2359;&#2366; &#2330;&#2369;&#2344;&#2375;";
"done" = "&#2361;&#2379; &#2327;&#2351;&#2366;";
"error" = "&#2340;&#2381;&#2352;&#2369;&#2335;&#2367;";
"ok" = "&#2336;&#2368;&#2325; &#2361;&#2376;";
"close" = "&#2348;&#2306;&#2342; &#2325;&#2352;&#2375;";</code></pre><h1><strong>Localization Helper</strong></h1><p>What we are going to do first is to create a helper class that will return the localized string for different texts as per the selected language.<br>Add a new swift file in Helpers folder namely <code>LocalizationHelper.swift</code> .<br>Create a new singleton class for this <code>LocalizationHelper</code>.</p><pre><code>class LocalizationHelper {
    public static func localize(_ key: String) -&gt; String {
        return NSLocalizedString(key, comment: "")
    }

    private static func localize(args: [CVarArg], key: String) -&gt; String {
        String(format: localize(key), args)
    }
}</code></pre><p>Above func <code>localize(:)</code>, will return the loclaized strings for both cases with or without arguments for localization where aruguments refers to the data to be inserted at run time.</p><pre><code>class LocalizationHelper {
    //  ------

    static var signInToAccount: String { localize("sign-in-to-account") }
    static var enterEmail: String { localize("enter-email") }
    static var email: String { localize("email") }
    static var enterPassword: String { localize("enter-password") }
    static var password: String { localize("password") }
    static var singIn: String { localize("sing-in") }
    static var signUpHere: String { localize("sign-up-here") }
    
    static var back: String { localize("back") }
    static var backToLogin: String { localize("back-to-login") }
    static var createNewAccount: String { localize("create-new-account") }
    static var confirmPassword: String { localize("confirm-password") }
    static var signUp: String { localize("sign-up") }
    static var accountAlreadyExists: String { localize("account-already-exists") }
    static var accountCreatedSuccessfully: String { localize("account-created-successfully") }
    static var invalidCredentials: String { localize("invalid-credentials") }
    
    static var selectLanguage: String { localize("select-language") }
    static var done: String { localize("done") }
    static var error: String { localize("error") }
    static var ok: String { localize("ok") }
    static var close: String { localize("close") }
    static func welcomeUser(_ args: [CVarArg]) -&gt; String {
        localize(args: args, key: "welcome-user")
    }
}</code></pre><p>Now, added static variables corresponding to each different texts present in entire project. So, if we haveb to access the transalted string for text &#8220;Sign in&#8221;, we simply will call &#8212; <code>LocalizationHelper.singIn</code>.</p><h1><strong>Localizable Extensions to create @</strong><em><strong>IBInspectable</strong></em><code> elements</code></h1><p>Let&#8217;s start with the starter project. Create a new swift file in Extensions folder <code>LocalizableExtensions.swift</code>. Add a protocol <code>StbIBLocalizable</code> (storyboard localizable) which our storyboard objects will conform for an adding an additional element.</p><pre><code>//  LocalizableExtensions.swift

import Foundation

protocol StbIBLocalizable {
    var localizedKey: String? { get set }
}</code></pre><p>To use this <code>StbIBLocalizable</code> protocol, we will use extensions of UILabels, UIButton,.. to conform to this protocol. Let&#8217;s start by adding extensions for UILabel in <code>LocalizableExtensions.swift</code> .</p><pre><code>extension UILabel: StbIBLocalizable {
    @IBInspectable var localizedKey: String? {
        get { nil }
        set(key) {
            if let key = key { text = LocalizationHelper.localize(key) }
        }
    }
}</code></pre><p>After conforming to the <code>StbIBLocalizable</code> protocol by UILabel, making variable <code>localizedKey</code> as an <code>@IBInspectable</code> element, you will see an additional field in the attribute inspector in main.storyboard. We can use this field to directly add the text and it will be automatically translated.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!uLJi!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cb09efe-7b17-4c0d-b47b-21fc279b925c_522x434.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!uLJi!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cb09efe-7b17-4c0d-b47b-21fc279b925c_522x434.png 424w, https://substackcdn.com/image/fetch/$s_!uLJi!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cb09efe-7b17-4c0d-b47b-21fc279b925c_522x434.png 848w, https://substackcdn.com/image/fetch/$s_!uLJi!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cb09efe-7b17-4c0d-b47b-21fc279b925c_522x434.png 1272w, https://substackcdn.com/image/fetch/$s_!uLJi!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cb09efe-7b17-4c0d-b47b-21fc279b925c_522x434.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!uLJi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cb09efe-7b17-4c0d-b47b-21fc279b925c_522x434.png" width="522" height="434" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/7cb09efe-7b17-4c0d-b47b-21fc279b925c_522x434.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:434,&quot;width&quot;:522,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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_!uLJi!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cb09efe-7b17-4c0d-b47b-21fc279b925c_522x434.png 424w, https://substackcdn.com/image/fetch/$s_!uLJi!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cb09efe-7b17-4c0d-b47b-21fc279b925c_522x434.png 848w, https://substackcdn.com/image/fetch/$s_!uLJi!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cb09efe-7b17-4c0d-b47b-21fc279b925c_522x434.png 1272w, https://substackcdn.com/image/fetch/$s_!uLJi!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F7cb09efe-7b17-4c0d-b47b-21fc279b925c_522x434.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&#8217;s add the text &#8220;enter-email&#8221; in the <code>localizedKey</code>, and run the he application in Hindi. You can run your application using different locales by <em>Option</em> + Clicking on the (Play) Start active scheme button, then going to Run &#8594; Options &#8594; App Language &#8594; Change to a supported language (Hindi in this case) &#8594; Click Run.</p><p>You will see that that the &#8220;Enter email&#8221; is being showed as &#8220;&#2312;&#2350;&#2375;&#2354; &#2342;&#2352;&#2381;&#2332; &#2325;&#2352;&#2375;&#2306;&#8221;.</p><p>Let&#8217;s add the extensions for other elements. You can customize the thsese as per your need.</p><pre><code>extension UIButton: StbIBLocalizable {
    @IBInspectable var localizedKey: String? {
        get { nil }
        set(key) {
            if let key = key {
                setTitle(LocalizationHelper.localize(key), for: .normal)
                setTitle(LocalizationHelper.localize(key), for: .highlighted)
                setTitle(LocalizationHelper.localize(key), for: .selected)
                setTitle(LocalizationHelper.localize(key), for: .disabled)
            }

        }
    }
}

extension UINavigationItem: StbIBLocalizable {
    @IBInspectable var localizedKey: String? {
        get { nil }
        set(key) {
            if let key = key { title = LocalizationHelper.localize(key) }
        }
    }
}

extension UIBarItem: StbIBLocalizable {
    @IBInspectable var localizedKey: String? {
        get { nil }
        set(key) {
            if let key = key { title = LocalizationHelper.localize(key) }
        }
    }
}

extension UITextField: StbIBLocalizable {
    @IBInspectable var localizedKey: String? {
        get { nil }
        set(key) {
            if let key = key {
                text = LocalizationHelper.localize(key)
                placeholder = LocalizationHelper.localize(key)
            }
        }
    }
}</code></pre><p>Add the localized key from strings file in the <code>localizedKey</code>in the attribute inspector for each objects. Now, we are done with the localizing the storyboard objects, let&#8217;s jump how to localize strings in the swift code.</p><p>Replace the label text in WelcomeViewController by using <code>LocalizationHelper</code> class member to get the translated string as per the current selected language &amp; our welcome page will look like this:</p><pre><code>override func viewDidLoad() {
    super.viewDidLoad()
    welcomeLabel.text = LocalizationHelper.welcomeUser([user!])
}</code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!fdyc!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdcc4c79-f506-4202-88ac-f917e95a1793_1020x1916.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!fdyc!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdcc4c79-f506-4202-88ac-f917e95a1793_1020x1916.png 424w, https://substackcdn.com/image/fetch/$s_!fdyc!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdcc4c79-f506-4202-88ac-f917e95a1793_1020x1916.png 848w, https://substackcdn.com/image/fetch/$s_!fdyc!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdcc4c79-f506-4202-88ac-f917e95a1793_1020x1916.png 1272w, https://substackcdn.com/image/fetch/$s_!fdyc!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdcc4c79-f506-4202-88ac-f917e95a1793_1020x1916.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!fdyc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdcc4c79-f506-4202-88ac-f917e95a1793_1020x1916.png" width="1020" height="1916" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/bdcc4c79-f506-4202-88ac-f917e95a1793_1020x1916.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1916,&quot;width&quot;:1020,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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_!fdyc!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdcc4c79-f506-4202-88ac-f917e95a1793_1020x1916.png 424w, https://substackcdn.com/image/fetch/$s_!fdyc!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdcc4c79-f506-4202-88ac-f917e95a1793_1020x1916.png 848w, https://substackcdn.com/image/fetch/$s_!fdyc!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdcc4c79-f506-4202-88ac-f917e95a1793_1020x1916.png 1272w, https://substackcdn.com/image/fetch/$s_!fdyc!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fbdcc4c79-f506-4202-88ac-f917e95a1793_1020x1916.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><h1><strong>How to manually change the app language?</strong></h1><p>Apple doesn&#8217;t suggest us to manually change the app language, but since we are doing it, we will create a new view controller that will gives us option to choose among the available app languages. We will use <code>UserDefaults</code> to store and track the current selected langauage.<br>Our app will initialize with selected langauage (base langauage if not any selected). Also, on change of selected langauage, we will revert the user to home page (login page in our case). So, let&#8217;s start the implemenataion.</p><p>Go to the <code>Extension</code> file, and add the following extension for the UserDefaults. We will store the current selected language with the <code>"i18n_language"</code> key and the variable <code>selectedLanguage</code> will be used to set and get the selected language.</p><p>If you want to learn more about the <code>UserDefaults</code> , you can go through this article <a href="https://rohit-13.medium.com/all-about-userdefaults-keychain-and-coredata-ios-53c8d0c7a0fb">here</a>.</p><pre><code>extension UserDefaults {
    var selectedLanguage: String? {
        get { string(forKey: "i18n_language") }
        set { set(newValue, forKey: "i18n_language") }
    }
}</code></pre><p>Also, we need to modify <code>func localize()</code> in our <code>LocalizationHelper</code> class, so that it checks the current selected language in UserDefaults &amp; return the translated strings as per the selected language.</p><pre><code>class LocalizationHelper {
    public static func localize(_ key: String) -&gt; String {
        if UserDefaults.standard.selectedLanguage == nil {
            UserDefaults.standard.selectedLanguage = "en"
            UserDefaults.standard.synchronize()
        }
        
        let lang = UserDefaults.standard.selectedLanguage
        guard let path = Bundle.main.path(forResource: lang, ofType: "lproj") else {
            return NSLocalizedString(key, comment: "")
        }
        
        let bundle = Bundle(path: path)
        return NSLocalizedString(key, bundle: bundle!, comment: "")
    }
    // -------
}</code></pre><h2><strong>SelectLanguageViewController</strong></h2><p>Till now, we have added all the necessary requirements for translating the strings as per the selected langauge saved in the UserDefaults. Now, let&#8217;s add a page for selecting the language.<br>I have created a new UITableViewController into the Main.storyboard and linked it to the class<code>SelectLanguageViewController</code>. Also, added a settings button onto the navigation right bar button item in the WelcomeViewController, which will redirect the user to the SelectLanguageVC page. The SelectLanguageVC tableview list items displays avialable language and is calculated from the localization bundle. So, here the code for the <code>SelectLanguageViewController</code>, <code>SelectLanguageViewModel</code>, <code>SelectLanguageTableViewCell</code> &amp; the <code>Language</code> model.</p><pre><code>class SelectLanguageViewController: UITableViewController {
    private let viewModel = SelectLanguageViewModel()

    override func viewDidLoad() {
        super.viewDidLoad()
        let doneButton = UIBarButtonItem(title: LocalizationHelper.done, style: .plain, target: self, action: #selector(self.doneButtonPressed))
        self.navigationItem.rightBarButtonItem = doneButton
    }
    
    @objc func doneButtonPressed() {
        if UserDefaults.standard.selectedLanguage != viewModel.selectedLanguage.code {
            UserDefaults.standard.selectedLanguage = viewModel.selectedLanguage.code
            SceneDelegate.shared?.reloadWindow()
        }
        else {
            self.dismiss(animated: true, completion: nil)
        }
    }

    // MARK: - Table view data source
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
        viewModel.availableLanguage.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! SelectLanguageTableViewCell
        cell.languageNameLabel.text = viewModel.availableLanguage[indexPath.row].name
        cell.accessoryType = viewModel.selectedLanguageIndex == indexPath.row ? .checkmark : .none
        return cell
    }
    
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        viewModel.selectedLanguageIndex = indexPath.row
        tableView.reloadData()
    }
}

struct Language {
    var code: String
    var name: String?
}

class SelectLanguageViewModel {
    var availableLanguage = [Language]()
    var selectedLanguageIndex: Int
    var selectedLanguage: Language {
        availableLanguage[selectedLanguageIndex]
    }

    init() {
        availableLanguage = Bundle.main.localizations
            .filter { $0 != "Base" }
            .map { Language(code: $0, name: Locale.current.localizedString(forLanguageCode: $0)) }
        
        selectedLanguageIndex = availableLanguage
            .map { $0.code }
            .firstIndex(of: UserDefaults.standard.selectedLanguage ?? "en") ?? 0
    }
}

class SelectLanguageTableViewCell: UITableViewCell {
    @IBOutlet weak var languageNameLabel: UILabel!
}</code></pre><p>So what I&#8217;m doing here first is to find the available languages for the tableview datasource. Also, I&#8217;m using the UserDefaults to track the current selected language, so when the done button is pressed, we reload the entire rootViewController window, and then all our strings are translated through the LocalizationHelper as per the current selected language.</p><p>To reload the entire rootViewController window, I had created a func <code>reloadWindow</code> in <code>SceneDelegate</code> which will set the window rootViewController as the new <code>instantiateInitialViewController</code> .</p><pre><code>class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    var window: UIWindow?
    static weak var shared: SceneDelegate?

    func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
        // -----
        Self.shared = self
    }
    
    // ----------------
    func reloadWindow() {
        let vc = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()!
        window?.rootViewController = vc
    }
}</code></pre><h1><strong>Here, is the final output</strong></h1><div class="image-gallery-embed" data-attrs="{&quot;gallery&quot;:{&quot;images&quot;:[{&quot;type&quot;:&quot;image/webp&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4304d86c-6482-40f7-9334-115c875c924c_1020x1916.webp&quot;},{&quot;type&quot;:&quot;image/webp&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4c485ba2-e070-4698-b28e-f72f2738bd65_1020x1916.webp&quot;},{&quot;type&quot;:&quot;image/webp&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/32d80ab6-5e06-4a23-9381-e0b29d039fb6_1020x1916.webp&quot;},{&quot;type&quot;:&quot;image/webp&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3a4810ad-91e4-479f-bb15-769b5c9af825_1020x1916.webp&quot;},{&quot;type&quot;:&quot;image/webp&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fc8ebc6b-3dc3-4f4e-8d92-4bf10b7c0c9b_1020x1916.webp&quot;},{&quot;type&quot;:&quot;image/webp&quot;,&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/aed5a4be-2cfd-4d60-a35e-c8d09df33410_1020x1916.webp&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/bd46dc70-6663-4e9b-98fc-e092cecf7bdc_1456x964.png&quot;}},&quot;isEditorNode&quot;:true}"></div><h1><strong>Summary</strong></h1><p>Hurray, we have now completed the better approach to add internationalization support in our app. Adding the internationalization support to an app by this approach is little less complex than the last one and can easily be done for multiple languages. Also, we have learned how we can add options to manually change the app language.<br>Here, is the <a href="https://github.com/rohit-13/InternationalizationDemo">github link</a> for the completed project.<br>You can also find the previous discussed approach <a href="https://tech.yellow.ai/p/ios-app-internationalizationi18n">here</a>.</p><p><strong>Thanks for Reading!<br>If you liked this article, please share and &#128079; so other people can read it too :)</strong></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tech.yellow.ai/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 Tech @ Yellow AI ! 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>]]></content:encoded></item><item><title><![CDATA[iOS app Internationalization(i18n) using Swift — Part1]]></title><description><![CDATA[While building an app, who doesn&#8217;t want to scale their app across the globe and make their app to be available in various local languages.]]></description><link>https://tech.yellow.ai/p/ios-app-internationalizationi18n</link><guid isPermaLink="false">https://tech.yellow.ai/p/ios-app-internationalizationi18n</guid><dc:creator><![CDATA[Rohit Kumar]]></dc:creator><pubDate>Wed, 20 Sep 2023 08:08:04 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!gas7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>While building an app, who doesn&#8217;t want to scale their app across the globe and make their app to be available in various local languages. But how one can achieve it, the answer is <strong>Internationalization.</strong></p><p>Are you developing an iOS application, but you do not know how to internationalize and localize your iOS app? If the answer is yes, then you are at the right place. In this article, we will see how to setup Internationalization and Localization in an iOS application using Swift.<br>This article will elaborate different approaches to add internationalization support in an iOS app and will also look into its implementation via code.</p><ul><li><p>Internationalization vs Localization</p></li><li><p>Setting-up the project for i18n</p></li><li><p>How do I add additional languages support to my app?</p></li><li><p>Localizing the Storyboards</p></li><li><p>How do I localize strings in my Swift code?</p></li><li><p>Consequences of this approach</p></li><li><p>What&#8217;s next to do ?</p></li></ul><p>A developer or an individual who is new to this internationalization concept often get confuse between these two words &#8220;Internationalization and Localization&#8221;. These are different but interconnected concepts.<br>So, what does these basically means? What&#8217;s differences between them?</p><blockquote><p><em>Internationalization (i18n) is process of making our app adaptable to different languages and regions. On the other hand, Localization (l10n) is process of translating our app to different languages.</em></p></blockquote><p>Internationalization is abbreviated as &#8220;i18n&#8221; as there are eighteen number of characters between &#8220;i&#8221; and &#8220;n&#8221;. Similarly, Localization is abreviated as &#8220;l10n&#8221; as number of characters between &#8220;l&#8221; and &#8220;n&#8221; equals ten.</p><h1><strong>Setting-up the project for i18n</strong></h1><p>Here&#8217;s a <strong><a href="https://github.com/rohit-13/InternationalizationDemo/tree/starter-project">starter-project</a></strong><a href="https://github.com/rohit-13/InternationalizationDemo/tree/starter-project"> </a>for you so that we can jump directly to the i18n implementation. Before that, let me explain you the project structure.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!gas7!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!gas7!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.png 424w, https://substackcdn.com/image/fetch/$s_!gas7!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.png 848w, https://substackcdn.com/image/fetch/$s_!gas7!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.png 1272w, https://substackcdn.com/image/fetch/$s_!gas7!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!gas7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.png" width="1456" height="715" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/b8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:715,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&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="" title="" srcset="https://substackcdn.com/image/fetch/$s_!gas7!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.png 424w, https://substackcdn.com/image/fetch/$s_!gas7!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.png 848w, https://substackcdn.com/image/fetch/$s_!gas7!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.png 1272w, https://substackcdn.com/image/fetch/$s_!gas7!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fb8139bb9-f7ec-4bba-b54c-e78673760cd0_2000x982.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>The <a href="https://github.com/rohit-13/InternationalizationDemo/tree/starter-project">starter-project</a> has a very simple layout, has only three view controllers: <code>SigninViewController</code>,  <code>SignupViewController </code>and a <code>WelcomeViewController</code> and a singleton class <code>KeychainHelper</code> to manage KeyChain services for authentication.</p><p>On the initialization of app, user lands on the &#8220;SignIn&#8221; page, where he/she has option to either sign in or go to &#8220;SignUp&#8221; page. On successful sign in, user gets redirected to &#8220;Welcome&#8221; page.</p><blockquote><p><em>In this project, I have used </em><code>KeyChain</code> services for data encryption and authentication.</p></blockquote><p>Download and run the <a href="https://github.com/rohit-13/InternationalizationDemo/tree/starter-project">starter-project</a> and go through the project once to understand it. Now, let&#8217;s start our i18n implementation.</p><h1><strong>How do I add additional languages support to my app?</strong></h1><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!tqO_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa163696-04aa-468c-a3c1-e6adf08c5e36_1400x890.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!tqO_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa163696-04aa-468c-a3c1-e6adf08c5e36_1400x890.png 424w, https://substackcdn.com/image/fetch/$s_!tqO_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa163696-04aa-468c-a3c1-e6adf08c5e36_1400x890.png 848w, https://substackcdn.com/image/fetch/$s_!tqO_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa163696-04aa-468c-a3c1-e6adf08c5e36_1400x890.png 1272w, https://substackcdn.com/image/fetch/$s_!tqO_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa163696-04aa-468c-a3c1-e6adf08c5e36_1400x890.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!tqO_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa163696-04aa-468c-a3c1-e6adf08c5e36_1400x890.png" width="1400" height="890" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/fa163696-04aa-468c-a3c1-e6adf08c5e36_1400x890.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:890,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&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_!tqO_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa163696-04aa-468c-a3c1-e6adf08c5e36_1400x890.png 424w, https://substackcdn.com/image/fetch/$s_!tqO_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa163696-04aa-468c-a3c1-e6adf08c5e36_1400x890.png 848w, https://substackcdn.com/image/fetch/$s_!tqO_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa163696-04aa-468c-a3c1-e6adf08c5e36_1400x890.png 1272w, https://substackcdn.com/image/fetch/$s_!tqO_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Ffa163696-04aa-468c-a3c1-e6adf08c5e36_1400x890.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>From the Project Navigator, select the project name <code>InternationalizationDemo</code>, make sure you are on Info segment. Then check the <code>Use Base Internationalization</code> and click on add <code>+</code> button.<br>Choose <code>Hindi(hi)</code>and for now let&#8217;s check both storyboards.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!QkEg!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50e640e5-b88f-411f-9882-853b87931059_1400x735.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!QkEg!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50e640e5-b88f-411f-9882-853b87931059_1400x735.png 424w, https://substackcdn.com/image/fetch/$s_!QkEg!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50e640e5-b88f-411f-9882-853b87931059_1400x735.png 848w, https://substackcdn.com/image/fetch/$s_!QkEg!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50e640e5-b88f-411f-9882-853b87931059_1400x735.png 1272w, https://substackcdn.com/image/fetch/$s_!QkEg!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50e640e5-b88f-411f-9882-853b87931059_1400x735.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!QkEg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50e640e5-b88f-411f-9882-853b87931059_1400x735.png" width="1400" height="735" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/50e640e5-b88f-411f-9882-853b87931059_1400x735.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:735,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&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_!QkEg!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50e640e5-b88f-411f-9882-853b87931059_1400x735.png 424w, https://substackcdn.com/image/fetch/$s_!QkEg!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50e640e5-b88f-411f-9882-853b87931059_1400x735.png 848w, https://substackcdn.com/image/fetch/$s_!QkEg!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50e640e5-b88f-411f-9882-853b87931059_1400x735.png 1272w, https://substackcdn.com/image/fetch/$s_!QkEg!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F50e640e5-b88f-411f-9882-853b87931059_1400x735.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><strong>Changes in project after adding a language</strong></h2><p>After adding a supported languages, you&#8217;ll realize some changes in your project. Let&#8217;s discuss these changes, and what it means for our goal of localization.<br>&#8226; Language folders: Xcode will generate <code>hi.lproj</code>direcory that will contain <code>Main.strings</code> for Hindi.<br>&#8226; Storyboard: <code>Main.storyboard</code> should now be a folder containing the base <code>Main.storyboard</code> and <code>Main.strings</code> of supported languages (Hindi here).<br>&#8226;<code>Main.strings</code>: Each object(labels, buttons,&#8230;) are added in this file with an unique ObjectID. <em>Don&#8217;t directly change this ObjectID for any item.</em></p><h2><strong>Localizing the Storyboards</strong></h2><p>Click on <code>Main.strings(Hindi)</code> to open it in the editor. You should already have an entry for the <strong>Sign in to your account</strong> label which will look something like this:</p><pre><code><code>/* Class = "UILabel"; text = "Sign in to your account"; ObjectID = "61H-Ar-Y7e"; */
"61H-Ar-Y7e.text" = "Sign in to your account";</code></code></pre><p>Replace the English translation with the Hindi translation. Do the same for all other items. Your <code>Main.strings(Hindi)</code>will look like this:</p><pre><code><code>/* Class = "UILabel"; text = "Sign in to your account"; ObjectID = "61H-Ar-Y7e"; */
"61H-Ar-Y7e.text" = "&#2309;&#2346;&#2344;&#2375; &#2309;&#2325;&#2366;&#2313;&#2306;&#2335; &#2350;&#2375;&#2306; &#2360;&#2366;&#2311;&#2344; &#2311;&#2344; &#2325;&#2352;&#2375;&#2306;";</code></code></pre><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!YQI0!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8618d1d-41f6-451c-badb-9207ebd95a60_1400x890.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!YQI0!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8618d1d-41f6-451c-badb-9207ebd95a60_1400x890.png 424w, https://substackcdn.com/image/fetch/$s_!YQI0!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8618d1d-41f6-451c-badb-9207ebd95a60_1400x890.png 848w, https://substackcdn.com/image/fetch/$s_!YQI0!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8618d1d-41f6-451c-badb-9207ebd95a60_1400x890.png 1272w, https://substackcdn.com/image/fetch/$s_!YQI0!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8618d1d-41f6-451c-badb-9207ebd95a60_1400x890.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!YQI0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8618d1d-41f6-451c-badb-9207ebd95a60_1400x890.png" width="1400" height="890" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e8618d1d-41f6-451c-badb-9207ebd95a60_1400x890.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:890,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&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_!YQI0!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8618d1d-41f6-451c-badb-9207ebd95a60_1400x890.png 424w, https://substackcdn.com/image/fetch/$s_!YQI0!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8618d1d-41f6-451c-badb-9207ebd95a60_1400x890.png 848w, https://substackcdn.com/image/fetch/$s_!YQI0!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8618d1d-41f6-451c-badb-9207ebd95a60_1400x890.png 1272w, https://substackcdn.com/image/fetch/$s_!YQI0!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe8618d1d-41f6-451c-badb-9207ebd95a60_1400x890.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>Now let&#8217;s run the application in Hindi to see if our localization worked. By default, every time you run the application, it uses the base language. You can run your application using different locales by <em>Option</em> + Clicking on the (Play) Start active scheme button, then going to Run &#8594; Options &#8594; App Language &#8594; Change to a supported language (Hindi in this case) &#8594; Click Run.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!-Z8O!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3409782a-8bc3-40ad-9494-7933a581a094_1400x890.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!-Z8O!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3409782a-8bc3-40ad-9494-7933a581a094_1400x890.png 424w, https://substackcdn.com/image/fetch/$s_!-Z8O!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3409782a-8bc3-40ad-9494-7933a581a094_1400x890.png 848w, https://substackcdn.com/image/fetch/$s_!-Z8O!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3409782a-8bc3-40ad-9494-7933a581a094_1400x890.png 1272w, https://substackcdn.com/image/fetch/$s_!-Z8O!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3409782a-8bc3-40ad-9494-7933a581a094_1400x890.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!-Z8O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3409782a-8bc3-40ad-9494-7933a581a094_1400x890.png" width="1400" height="890" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/3409782a-8bc3-40ad-9494-7933a581a094_1400x890.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:890,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&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_!-Z8O!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3409782a-8bc3-40ad-9494-7933a581a094_1400x890.png 424w, https://substackcdn.com/image/fetch/$s_!-Z8O!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3409782a-8bc3-40ad-9494-7933a581a094_1400x890.png 848w, https://substackcdn.com/image/fetch/$s_!-Z8O!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3409782a-8bc3-40ad-9494-7933a581a094_1400x890.png 1272w, https://substackcdn.com/image/fetch/$s_!-Z8O!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F3409782a-8bc3-40ad-9494-7933a581a094_1400x890.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>Our app looks like this after adding language support in Hindi.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!AGTw!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36ed354-99c5-4ebc-b827-0c5329dc42fb_496x1112.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!AGTw!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36ed354-99c5-4ebc-b827-0c5329dc42fb_496x1112.png 424w, https://substackcdn.com/image/fetch/$s_!AGTw!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36ed354-99c5-4ebc-b827-0c5329dc42fb_496x1112.png 848w, https://substackcdn.com/image/fetch/$s_!AGTw!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36ed354-99c5-4ebc-b827-0c5329dc42fb_496x1112.png 1272w, https://substackcdn.com/image/fetch/$s_!AGTw!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36ed354-99c5-4ebc-b827-0c5329dc42fb_496x1112.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!AGTw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36ed354-99c5-4ebc-b827-0c5329dc42fb_496x1112.png" width="302" height="677.0645161290323" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d36ed354-99c5-4ebc-b827-0c5329dc42fb_496x1112.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1112,&quot;width&quot;:496,&quot;resizeWidth&quot;:302,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&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_!AGTw!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36ed354-99c5-4ebc-b827-0c5329dc42fb_496x1112.png 424w, https://substackcdn.com/image/fetch/$s_!AGTw!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36ed354-99c5-4ebc-b827-0c5329dc42fb_496x1112.png 848w, https://substackcdn.com/image/fetch/$s_!AGTw!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36ed354-99c5-4ebc-b827-0c5329dc42fb_496x1112.png 1272w, https://substackcdn.com/image/fetch/$s_!AGTw!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd36ed354-99c5-4ebc-b827-0c5329dc42fb_496x1112.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><strong>How do I localize strings in my Swift code?</strong></h2><p>If you go to the Welcome page, you will notice that the <code>welcomeLabel</code> is not localized because we are programmatically adding the code here <code>welcomeLabel.text = &#8220;Welcome \(user ?? &#8220;&#8221;)".</code> So, how do we localize our swift code ?<br>&#8226; Select File &#8594; New File &#8594; search for Strings File &#8594; keep the name <strong>Localizable</strong> as default.<br>&#8226; Xcode will generate <code>Localizable.strings</code> file. In the file inspector, you will see <strong>localization </strong>panel. Click localize and select &#8220;Localize&#8221;.<br>&#8226; Again, in file inspector, check <strong>Hindi </strong>in<strong> localization </strong>panel. Xcode will generate two <code>Localizable.strings</code> files for both English and Hindi.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Txtv!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd51b9ca1-1765-4f66-89ed-b9837d8047a9_1480x1052.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Txtv!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd51b9ca1-1765-4f66-89ed-b9837d8047a9_1480x1052.png 424w, https://substackcdn.com/image/fetch/$s_!Txtv!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd51b9ca1-1765-4f66-89ed-b9837d8047a9_1480x1052.png 848w, https://substackcdn.com/image/fetch/$s_!Txtv!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd51b9ca1-1765-4f66-89ed-b9837d8047a9_1480x1052.png 1272w, https://substackcdn.com/image/fetch/$s_!Txtv!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd51b9ca1-1765-4f66-89ed-b9837d8047a9_1480x1052.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Txtv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd51b9ca1-1765-4f66-89ed-b9837d8047a9_1480x1052.png" width="1456" height="1035" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/d51b9ca1-1765-4f66-89ed-b9837d8047a9_1480x1052.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1035,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&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_!Txtv!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd51b9ca1-1765-4f66-89ed-b9837d8047a9_1480x1052.png 424w, https://substackcdn.com/image/fetch/$s_!Txtv!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd51b9ca1-1765-4f66-89ed-b9837d8047a9_1480x1052.png 848w, https://substackcdn.com/image/fetch/$s_!Txtv!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd51b9ca1-1765-4f66-89ed-b9837d8047a9_1480x1052.png 1272w, https://substackcdn.com/image/fetch/$s_!Txtv!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fd51b9ca1-1765-4f66-89ed-b9837d8047a9_1480x1052.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 class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!aFYh!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc319d52e-f519-4fb6-9110-1a95860fe90f_1618x962.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!aFYh!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc319d52e-f519-4fb6-9110-1a95860fe90f_1618x962.png 424w, https://substackcdn.com/image/fetch/$s_!aFYh!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc319d52e-f519-4fb6-9110-1a95860fe90f_1618x962.png 848w, https://substackcdn.com/image/fetch/$s_!aFYh!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc319d52e-f519-4fb6-9110-1a95860fe90f_1618x962.png 1272w, https://substackcdn.com/image/fetch/$s_!aFYh!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc319d52e-f519-4fb6-9110-1a95860fe90f_1618x962.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!aFYh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc319d52e-f519-4fb6-9110-1a95860fe90f_1618x962.png" width="1456" height="866" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/c319d52e-f519-4fb6-9110-1a95860fe90f_1618x962.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:866,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&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_!aFYh!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc319d52e-f519-4fb6-9110-1a95860fe90f_1618x962.png 424w, https://substackcdn.com/image/fetch/$s_!aFYh!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc319d52e-f519-4fb6-9110-1a95860fe90f_1618x962.png 848w, https://substackcdn.com/image/fetch/$s_!aFYh!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc319d52e-f519-4fb6-9110-1a95860fe90f_1618x962.png 1272w, https://substackcdn.com/image/fetch/$s_!aFYh!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fc319d52e-f519-4fb6-9110-1a95860fe90f_1618x962.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 class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!HEwC!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40806463-1000-45d8-a9e9-9081df8be713_1400x950.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!HEwC!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40806463-1000-45d8-a9e9-9081df8be713_1400x950.png 424w, https://substackcdn.com/image/fetch/$s_!HEwC!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40806463-1000-45d8-a9e9-9081df8be713_1400x950.png 848w, https://substackcdn.com/image/fetch/$s_!HEwC!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40806463-1000-45d8-a9e9-9081df8be713_1400x950.png 1272w, https://substackcdn.com/image/fetch/$s_!HEwC!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40806463-1000-45d8-a9e9-9081df8be713_1400x950.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!HEwC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40806463-1000-45d8-a9e9-9081df8be713_1400x950.png" width="1400" height="950" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/40806463-1000-45d8-a9e9-9081df8be713_1400x950.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:950,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&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_!HEwC!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40806463-1000-45d8-a9e9-9081df8be713_1400x950.png 424w, https://substackcdn.com/image/fetch/$s_!HEwC!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40806463-1000-45d8-a9e9-9081df8be713_1400x950.png 848w, https://substackcdn.com/image/fetch/$s_!HEwC!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40806463-1000-45d8-a9e9-9081df8be713_1400x950.png 1272w, https://substackcdn.com/image/fetch/$s_!HEwC!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F40806463-1000-45d8-a9e9-9081df8be713_1400x950.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>We now have two localizable.strings file &#8212; one for the base language and other one for the Hindi.</p><p>A <strong>.strings</strong> file stores key-value pairs, just like a <code>Dictionary</code>. Conventional practice uses the base language translation as the key. The file has a specific, but simple, format:</p><pre><code><code>"KEY" = "CONTENT";</code></code></pre><p>Subsequently, let&#8217;s add the key and value pair text used in the Localizable. strings. Below is an example where I added the localization for <code>welcomeLabel</code></p><pre><code><code>//  Localizable (English)
"Welcome %@" = "Welcome %@";</code></code></pre><pre><code><code>//  Localizable (Hindi)
"Welcome %@" = "&#2360;&#2381;&#2357;&#2366;&#2327;&#2340; &#2361;&#2376; %@";</code></code></pre><p><code>NSLocalizedString(_:tableName:bundle:value:comment:)</code> is the primary tool you use in your code to access these localized strings. The <code>tableName</code>, <code>bundle</code>, and <code>value</code> parameters all have default values so you normally specify only the <code>key</code> and the <code>comment</code>. The <code>comment</code> parameter is there for you to provide a hint to translators as to what purpose this string serves in your app&#8217;s user experience.</p><blockquote><p><em>Let&#8217;s say we have a key-value pair in .strings file as<br>&#8220;welcome rohit&#8221; = &#8220;&#2360;&#2381;&#2357;&#2366;&#2327;&#2340; &#2361;&#2376; &#2352;&#2379;&#2361;&#2367;&#2340;&#8221;;</em></p><p><em>Here, we can update the text of </em><code>welcomeLabel</code> using<code>NSLocalizedString(:)</code> to make it localizable.<br><code>welcomeLabel.text = NSLocalizedString(&#8220;welcome rohit&#8221;, comment: &#8220;welcome&#8221;)</code></p><p><em>&#128161; We can include format specifiers in either the key or the value portion of the string to allow you to insert real data at run time.</em></p></blockquote><p>Open <code>WelcomeViewController</code> and add the following code in <code>viewDidLoad()</code> method.</p><pre><code><code>override func viewDidLoad() {
    super.viewDidLoad()
    let formatString = NSLocalizedString("Welcome %@", comment: "welcome user")
    welcomeLabel.text = String.localizedStringWithFormat(formatString, user!)
}</code></code></pre><p>Now, run the app and you will see that our <code>welcomeLabel</code> in <code>WelcomeViewController</code> is now able to localized as per the selected language. Also, the user details in <code>welcomeLabel</code> dynamically get updated since we added format specifiers while localizing it.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!5Bcq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6a8e3a9-280b-43da-be0a-9b20f578c4b3_496x1112.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!5Bcq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6a8e3a9-280b-43da-be0a-9b20f578c4b3_496x1112.png 424w, https://substackcdn.com/image/fetch/$s_!5Bcq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6a8e3a9-280b-43da-be0a-9b20f578c4b3_496x1112.png 848w, https://substackcdn.com/image/fetch/$s_!5Bcq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6a8e3a9-280b-43da-be0a-9b20f578c4b3_496x1112.png 1272w, https://substackcdn.com/image/fetch/$s_!5Bcq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6a8e3a9-280b-43da-be0a-9b20f578c4b3_496x1112.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!5Bcq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6a8e3a9-280b-43da-be0a-9b20f578c4b3_496x1112.png" width="314" height="703.9677419354839" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/a6a8e3a9-280b-43da-be0a-9b20f578c4b3_496x1112.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:1112,&quot;width&quot;:496,&quot;resizeWidth&quot;:314,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:&quot;&quot;,&quot;type&quot;:null,&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_!5Bcq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6a8e3a9-280b-43da-be0a-9b20f578c4b3_496x1112.png 424w, https://substackcdn.com/image/fetch/$s_!5Bcq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6a8e3a9-280b-43da-be0a-9b20f578c4b3_496x1112.png 848w, https://substackcdn.com/image/fetch/$s_!5Bcq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6a8e3a9-280b-43da-be0a-9b20f578c4b3_496x1112.png 1272w, https://substackcdn.com/image/fetch/$s_!5Bcq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fa6a8e3a9-280b-43da-be0a-9b20f578c4b3_496x1112.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><h1><strong>Consequences of this approach</strong></h1><p>Now, we have completed the i18n implementation and our app is ready for both Hindi &amp; English (base) language. But, there are some consequences in the approach we have taken for this implementation.</p><blockquote><p><em>Let&#8217;s take a scenario, Ram is an iOS developer working on a large and a complex app and now he wants to add i18n support for multiple languages (let's say five different languages). He take the above mentioned approach for the implementation. <strong>What will happen next ?<br></strong>&#8226; Xcode will generate five </em><code>Main.strings</code> for <code>Main.storyboard</code> localization and Ram will have to manually add translated strings for all objects (labels, buttons,&#8230;).<br>&#8226; Same this have to be done also for <code>.xib</code> files.<br>&#8226; High changes of making mistake of altering objectID.<br>&#8226; A very time consuming and an inefficient approach.</p></blockquote><h1><strong>What to do next ?</strong></h1><p>In the next continuation part of this article, we will look into another approach to overcome these consequences. Also, we will also learn about <em>how to programmatically add language switching.<br></em><a href="https://github.com/rohit-13/InternationalizationDemo/tree/storyboard-internationalization">Here</a> is the github link for the completed project using the above approach.<br>You can find next part <a href="https://tech.yellow.ai/p/ios-app-internationalizationi18n-982">here</a>.</p><p>Thanks for Reading!<br>If you liked this article, please share and &#128079; so other people can read it too :)</p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tech.yellow.ai/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 Tech @ Yellow AI ! 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>]]></content:encoded></item><item><title><![CDATA[Druid Monitoring]]></title><description><![CDATA[The way we did it]]></description><link>https://tech.yellow.ai/p/druid-monitoring</link><guid isPermaLink="false">https://tech.yellow.ai/p/druid-monitoring</guid><dc:creator><![CDATA[Praneeth Kumar Reddy Ballarapu]]></dc:creator><pubDate>Wed, 20 Sep 2023 06:28:25 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!KenZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!KenZ!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!KenZ!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp 424w, https://substackcdn.com/image/fetch/$s_!KenZ!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp 848w, https://substackcdn.com/image/fetch/$s_!KenZ!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp 1272w, https://substackcdn.com/image/fetch/$s_!KenZ!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!KenZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp" width="1126" height="485" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:485,&quot;width&quot;:1126,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:13704,&quot;alt&quot;:null,&quot;title&quot;:null,&quot;type&quot;:&quot;image/webp&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_!KenZ!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp 424w, https://substackcdn.com/image/fetch/$s_!KenZ!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp 848w, https://substackcdn.com/image/fetch/$s_!KenZ!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp 1272w, https://substackcdn.com/image/fetch/$s_!KenZ!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F858e1df6-5caa-4eda-9e91-20c171db50fb_1126x485.webp 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>Monitoring druid query execution, ingestion, and coordination is essential for production clusters which are powering the user-facing dashboards. The expectation of these dashboards/widgets is to be loaded in a few seconds with near-realtime data. So monitoring the health of the druid cluster is required for production setups.</p><h1><strong>How can I emit the monitoring metrics?</strong></h1><p>We can configure Druid to <strong><a href="https://druid.apache.org/docs/latest/configuration/#enabling-metrics">emit metrics</a></strong> that are essential for monitoring query execution, ingestion, coordination, and so on.</p><p>To know more about all the metrics refer to the <a href="https://druid.apache.org/docs/latest/operations/metrics/">official documentation</a></p><h1><strong>Monitors Configuration:</strong></h1><p>We need to use the monitors to monitor the respective processes to collect the metrics. Add this config in <code>common.runtime.properties</code></p><pre><code><code>druid.monitoring.monitors=["org.apache.druid.client.cache.CacheMonitor", "org.apache.druid.java.util.metrics.JvmMonitor", "org.apache.druid.java.util.metrics.CpuAcctDeltaMonitor", "org.apache.druid.java.util.metrics.JvmThreadsMonitor", "org.apache.druid.server.metrics.EventReceiverFirehoseMonitor", "org.apache.druid.server.metrics.TaskCountStatsMonitor"]</code></code></pre><p>Most of the production druid clusters will be running in a <a href="https://druid.apache.org/docs/latest/tutorials/cluster/">clustered deployment</a> where we will be running master (coordinator, overload), data(middleManager, historical), and query(router, broker) nodes separately in different VMs</p><p>So we need to configure the <code>druid.monitoring.monitors</code> property according to the process we are running.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!2Aw_!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f93a620-02bf-4aba-b7ce-374498f85895_925x367.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!2Aw_!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f93a620-02bf-4aba-b7ce-374498f85895_925x367.png 424w, https://substackcdn.com/image/fetch/$s_!2Aw_!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f93a620-02bf-4aba-b7ce-374498f85895_925x367.png 848w, https://substackcdn.com/image/fetch/$s_!2Aw_!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f93a620-02bf-4aba-b7ce-374498f85895_925x367.png 1272w, https://substackcdn.com/image/fetch/$s_!2Aw_!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f93a620-02bf-4aba-b7ce-374498f85895_925x367.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!2Aw_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f93a620-02bf-4aba-b7ce-374498f85895_925x367.png" width="925" height="367" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4f93a620-02bf-4aba-b7ce-374498f85895_925x367.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:367,&quot;width&quot;:925,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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_!2Aw_!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f93a620-02bf-4aba-b7ce-374498f85895_925x367.png 424w, https://substackcdn.com/image/fetch/$s_!2Aw_!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f93a620-02bf-4aba-b7ce-374498f85895_925x367.png 848w, https://substackcdn.com/image/fetch/$s_!2Aw_!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f93a620-02bf-4aba-b7ce-374498f85895_925x367.png 1272w, https://substackcdn.com/image/fetch/$s_!2Aw_!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4f93a620-02bf-4aba-b7ce-374498f85895_925x367.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">Process level monitors supported</figcaption></figure></div><p>Example:</p><p>Master &#8212; (Coordinator-Overlord)</p><pre><code>druid.monitoring.monitors=["org.apache.druid.client.cache.CacheMonitor", "org.apache.druid.java.util.metrics.JvmMonitor", "org.apache.druid.java.util.metrics.CpuAcctDeltaMonitor", "org.apache.druid.java.util.metrics.JvmThreadsMonitor", "org.apache.druid.server.metrics.EventReceiverFirehoseMonitor", "org.apache.druid.server.metrics.TaskCountStatsMonitor"]</code></pre><p>Data &#8212; (Historical, MiddleManager)</p><pre><code>druid.monitoring.monitors=["org.apache.druid.client.cache.CacheMonitor", "org.apache.druid.java.util.metrics.JvmMonitor", "org.apache.druid.java.util.metrics.CpuAcctDeltaMonitor", "org.apache.druid.java.util.metrics.JvmThreadsMonitor", "org.apache.druid.server.metrics.EventReceiverFirehoseMonitor"]</code></pre><p>Query &#8212; (Broker, Router)</p><pre><code>druid.monitoring.monitors=["org.apache.druid.client.cache.CacheMonitor", "org.apache.druid.java.util.metrics.JvmMonitor", "org.apache.druid.java.util.metrics.CpuAcctDeltaMonitor", "org.apache.druid.java.util.metrics.JvmThreadsMonitor", "org.apache.druid.server.metrics.EventReceiverFirehoseMonitor", "org.apache.druid.server.metrics.QueryCountStatsMonitor"]</code></pre><h1><strong>Emitter Configuration:</strong></h1><p>We need to add/edit the following config in the <code>common.runtime.properties</code> file to enable the emitter which emits metrics to an HTTP endpoint.</p><pre><code>druid.emitter=http
druid.emitter.http.recipientBaseUrl=http://{{druid_exporter_host}}:{{druid_exporter_port}}/druid</code></pre><p>Restart the nodes/processes after adding the above emitter and monitoring the config</p><h1><strong>Druid Exporter:</strong></h1><p>To collect and export metrics from druid we have an open-source druid exporter from Opstree &#8212; <a href="https://github.com/opstree/druid-exporter">https://github.com/opstree/druid-exporter</a></p><h2><strong>Installation:</strong></h2><p>We can deploy the druid exporter using</p><ol><li><p>releases &#8212; <a href="https://github.com/opstree/druid-exporter/releases">https://github.com/opstree/druid-exporter/releases</a></p></li><li><p>Kubernetes &#8212; <a href="https://github.com/opstree/druid-exporter/tree/master/manifests">https://github.com/opstree/druid-exporter/tree/master/manifests</a></p></li><li><p>docker-compose &#8212; <a href="https://github.com/opstree/druid-exporter/tree/master/compose">https://github.com/opstree/druid-exporter/tree/master/compose</a></p></li></ol><p>I will be going with release deployment directly &#8212; running druid exporter in one of the master nodes</p><pre><code>wget https://github.com/opstree/druid-exporter/releases/download/v0.11/druid-exporter-v0.11-linux-amd64.tar.gz
tar -xvzf druid-exporter-v0.11-linux-amd64.tar.gz</code></pre><p>Let&#8217;s create a <code>systemd</code> file to run the druid-exporter</p><pre><code>[Unit]
Description=Druid Exporter
Documentation=https://github.com/opstree/druid-exporter
Requires=network.target
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt
User=root
Group=root
ExecStart=/PATH_TO_DOWNLOADED_FOLDER/druid-exporter -p 8020 -d DRUID_COORDINATOR_OR_ROUTER_URL --druid.user="" --druid.password="" --metrics-cleanup-ttl=15 --no-histogram
[Install]
WantedBy=default.target</code></pre><p>Available options and flags &#8212; <a href="https://github.com/opstree/druid-exporter#available-options-or-flags">https://github.com/opstree/druid-exporter#available-options-or-flags</a></p><p>Enable the <code>systemd</code> file</p><pre><code>systemctl enable druid-exporter.service</code></pre><p>Start the druid-exporter</p><pre><code>systemctl start druid-exporter</code></pre><p>Verify the installation and check the metrics in the endpoint</p><pre><code>curl http://druid_export_host:port/metrics</code></pre><h1><strong>Grafana dashboard:</strong></h1><p>Cool, we have emitted, collected, and exported the monitoring metrics to Prometheus. Now it&#8217;s time to visualize and create alerts (if needed).</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!wTri!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9692d347-1703-4932-8fc0-0f40d7ca697a_1400x482.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!wTri!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9692d347-1703-4932-8fc0-0f40d7ca697a_1400x482.png 424w, https://substackcdn.com/image/fetch/$s_!wTri!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9692d347-1703-4932-8fc0-0f40d7ca697a_1400x482.png 848w, https://substackcdn.com/image/fetch/$s_!wTri!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9692d347-1703-4932-8fc0-0f40d7ca697a_1400x482.png 1272w, https://substackcdn.com/image/fetch/$s_!wTri!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9692d347-1703-4932-8fc0-0f40d7ca697a_1400x482.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!wTri!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9692d347-1703-4932-8fc0-0f40d7ca697a_1400x482.png" width="1400" height="482" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/9692d347-1703-4932-8fc0-0f40d7ca697a_1400x482.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:482,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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_!wTri!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9692d347-1703-4932-8fc0-0f40d7ca697a_1400x482.png 424w, https://substackcdn.com/image/fetch/$s_!wTri!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9692d347-1703-4932-8fc0-0f40d7ca697a_1400x482.png 848w, https://substackcdn.com/image/fetch/$s_!wTri!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9692d347-1703-4932-8fc0-0f40d7ca697a_1400x482.png 1272w, https://substackcdn.com/image/fetch/$s_!wTri!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F9692d347-1703-4932-8fc0-0f40d7ca697a_1400x482.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">Druid Overview &amp; Broker query time, bytes</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ml2R!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b257a62-5d6f-4957-805c-45a46e41dc46_1400x451.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ml2R!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b257a62-5d6f-4957-805c-45a46e41dc46_1400x451.png 424w, https://substackcdn.com/image/fetch/$s_!Ml2R!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b257a62-5d6f-4957-805c-45a46e41dc46_1400x451.png 848w, https://substackcdn.com/image/fetch/$s_!Ml2R!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b257a62-5d6f-4957-805c-45a46e41dc46_1400x451.png 1272w, https://substackcdn.com/image/fetch/$s_!Ml2R!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b257a62-5d6f-4957-805c-45a46e41dc46_1400x451.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ml2R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b257a62-5d6f-4957-805c-45a46e41dc46_1400x451.png" width="1400" height="451" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/4b257a62-5d6f-4957-805c-45a46e41dc46_1400x451.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:451,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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_!Ml2R!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b257a62-5d6f-4957-805c-45a46e41dc46_1400x451.png 424w, https://substackcdn.com/image/fetch/$s_!Ml2R!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b257a62-5d6f-4957-805c-45a46e41dc46_1400x451.png 848w, https://substackcdn.com/image/fetch/$s_!Ml2R!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b257a62-5d6f-4957-805c-45a46e41dc46_1400x451.png 1272w, https://substackcdn.com/image/fetch/$s_!Ml2R!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F4b257a62-5d6f-4957-805c-45a46e41dc46_1400x451.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">Historical Overview</figcaption></figure></div><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!0keX!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0145037a-b1bf-4d42-9338-d119d04713c0_1400x500.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!0keX!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0145037a-b1bf-4d42-9338-d119d04713c0_1400x500.png 424w, https://substackcdn.com/image/fetch/$s_!0keX!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0145037a-b1bf-4d42-9338-d119d04713c0_1400x500.png 848w, https://substackcdn.com/image/fetch/$s_!0keX!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0145037a-b1bf-4d42-9338-d119d04713c0_1400x500.png 1272w, https://substackcdn.com/image/fetch/$s_!0keX!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0145037a-b1bf-4d42-9338-d119d04713c0_1400x500.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!0keX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0145037a-b1bf-4d42-9338-d119d04713c0_1400x500.png" width="1400" height="500" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0145037a-b1bf-4d42-9338-d119d04713c0_1400x500.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:500,&quot;width&quot;:1400,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:null,&quot;alt&quot;:&quot;&quot;,&quot;title&quot;:null,&quot;type&quot;:null,&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_!0keX!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0145037a-b1bf-4d42-9338-d119d04713c0_1400x500.png 424w, https://substackcdn.com/image/fetch/$s_!0keX!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0145037a-b1bf-4d42-9338-d119d04713c0_1400x500.png 848w, https://substackcdn.com/image/fetch/$s_!0keX!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0145037a-b1bf-4d42-9338-d119d04713c0_1400x500.png 1272w, https://substackcdn.com/image/fetch/$s_!0keX!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0145037a-b1bf-4d42-9338-d119d04713c0_1400x500.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">JVM usage, ingestion count, lag</figcaption></figure></div><p>We have added more panels and visualization to the <a href="https://grafana.com/grafana/dashboards/12155-druid-druid-overview/">existing dashboard provided by Opstree</a>. Download the Grafana dashboard JSON from <a href="https://cdn.yellowmessenger.com/QvIXgf9vjKXU1695198589311.json">here</a>.</p><p>Corrections/suggestions are welcome. Thanks for reading.</p><p><strong>References:</strong></p><p><a href="https://github.com/opstree/druid-exporter">https://github.com/opstree/druid-exporter</a></p><p><a href="https://druid.apache.org/docs/latest/configuration/#enabling-metrics">https://druid.apache.org/docs/latest/configuration/#enabling-metrics</a></p><p><a href="https://druid.apache.org/docs/latest/operations/metrics">https://druid.apache.org/docs/latest/operations/metrics</a></p><div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://tech.yellow.ai/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 Tech @ Yellow AI ! 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>]]></content:encoded></item><item><title><![CDATA[Navigating the LLM Landscape at Yellow.ai]]></title><description><![CDATA[The LLM Revolution and the Need for Change]]></description><link>https://tech.yellow.ai/p/navigating-the-llm-landscape-at-yellowai</link><guid isPermaLink="false">https://tech.yellow.ai/p/navigating-the-llm-landscape-at-yellowai</guid><dc:creator><![CDATA[Jaya Kishore Reddy]]></dc:creator><pubDate>Mon, 11 Sep 2023 19:12:09 GMT</pubDate><enclosure url="https://substackcdn.com/image/fetch/$s_!OzRq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!OzRq!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!OzRq!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.png 424w, https://substackcdn.com/image/fetch/$s_!OzRq!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.png 848w, https://substackcdn.com/image/fetch/$s_!OzRq!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.png 1272w, https://substackcdn.com/image/fetch/$s_!OzRq!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!OzRq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.png" width="1456" height="645" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/e4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:645,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:488124,&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_!OzRq!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.png 424w, https://substackcdn.com/image/fetch/$s_!OzRq!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.png 848w, https://substackcdn.com/image/fetch/$s_!OzRq!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.png 1272w, https://substackcdn.com/image/fetch/$s_!OzRq!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2Fe4683f57-d8df-45e1-995f-e48d156e3086_2782x1232.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></p><h3>The LLM Revolution and the Need for Change</h3><p>The digital age introduced the world to a series of innovations, with Large Language Models (LLMs) like Chat GPT standing out prominently. These models, with their vast knowledge base and intricate design, transformed industries overnight. However, as we at Yellow.ai meticulously analyzed their integration into real-world applications, potential hurdles became evident. Imagine a customer support scenario where a customer is on a call with a voice-based assistant, driven by  LLMs, With the current state-of-the-art OpenAI&#8217;s gpt4 takes its own sweet time to respond. This gives a very bad experience to the end user who is waiting for help. Beyond just the user experience, the cost of inference is also very high for these gigantic models. With increasing reliance on API-based solutions, the unpredictability of costs and response times made it clear: a paradigm shift was essential.</p><p></p><h3>An Orthogonal Shift: Task-Specific Fine-Tuning</h3><p>While the potential of LLMs like Llama was widely recognized, there was no comprehensive knowledge about how to fine-tune them effectively. At Yellow.ai, we discerned a unique opportunity. Instead of a generalized approach, why not hone our efforts on tasks &#8212; the very core of any conversation? This perspective shifted our focus towards models like the 7 billion, 13 billion, and 33 billion parameter versions of Llama. With these distinct models, each was meticulously crafted for specific conversational tasks. Under this  framework, our ML/Data Science team invested their expertise, ensuring each model was perfectly calibrated for its designated role in the conversational ai pipeline.</p><div class="captioned-image-container"><figure><a class="image-link image2 is-viewable-img" target="_blank" href="https://substackcdn.com/image/fetch/$s_!Ko5X!,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0296014e-de8e-4126-b048-36843f085ac0_2872x1604.png" data-component-name="Image2ToDOM"><div class="image2-inset"><picture><source type="image/webp" srcset="https://substackcdn.com/image/fetch/$s_!Ko5X!,w_424,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0296014e-de8e-4126-b048-36843f085ac0_2872x1604.png 424w, https://substackcdn.com/image/fetch/$s_!Ko5X!,w_848,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0296014e-de8e-4126-b048-36843f085ac0_2872x1604.png 848w, https://substackcdn.com/image/fetch/$s_!Ko5X!,w_1272,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0296014e-de8e-4126-b048-36843f085ac0_2872x1604.png 1272w, https://substackcdn.com/image/fetch/$s_!Ko5X!,w_1456,c_limit,f_webp,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0296014e-de8e-4126-b048-36843f085ac0_2872x1604.png 1456w" sizes="100vw"><img src="https://substackcdn.com/image/fetch/$s_!Ko5X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0296014e-de8e-4126-b048-36843f085ac0_2872x1604.png" width="1456" height="813" data-attrs="{&quot;src&quot;:&quot;https://substack-post-media.s3.amazonaws.com/public/images/0296014e-de8e-4126-b048-36843f085ac0_2872x1604.png&quot;,&quot;srcNoWatermark&quot;:null,&quot;fullscreen&quot;:null,&quot;imageSize&quot;:null,&quot;height&quot;:813,&quot;width&quot;:1456,&quot;resizeWidth&quot;:null,&quot;bytes&quot;:819455,&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;: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_!Ko5X!,w_424,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0296014e-de8e-4126-b048-36843f085ac0_2872x1604.png 424w, https://substackcdn.com/image/fetch/$s_!Ko5X!,w_848,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0296014e-de8e-4126-b048-36843f085ac0_2872x1604.png 848w, https://substackcdn.com/image/fetch/$s_!Ko5X!,w_1272,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0296014e-de8e-4126-b048-36843f085ac0_2872x1604.png 1272w, https://substackcdn.com/image/fetch/$s_!Ko5X!,w_1456,c_limit,f_auto,q_auto:good,fl_progressive:steep/https%3A%2F%2Fsubstack-post-media.s3.amazonaws.com%2Fpublic%2Fimages%2F0296014e-de8e-4126-b048-36843f085ac0_2872x1604.png 1456w" sizes="100vw"></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><h3>Efficiency, Cost &amp; Accuracy</h3><p>In our quest for superior conversational AI, merely redesigning the fine-tuning process wasn't enough. We ventured further into the realm of technological innovations. Quantization techniques became our trusted ally in this journey, offering us a dual advantage: enhanced model performance and substantial cost savings. This restructuring allowed us to create a tiered system. Smaller, more efficient models tackled foundational tasks, ensuring swift and accurate responses. This, in turn, significantly reduced the chances of hallucinations. </p><p></p><h3>The Road Ahead</h3><p>While we continue our innovations, we humbly acknowledge the powerhouses of the LLM world. Models such as GPT-4 are in a league of their own, offering unmatched insights and depth. However, with our revamped strategy, their deployment is more strategic. By ensuring they are used where their intricate understanding is indispensable, we balance computational prowess with practicality. The advent of LLMs has opened doors we hadn't imagined. </p><p></p><p>Our dream of realizing a staggering 90% automation rate in customer support no longer seems a distant star but a tangible reality. At Yellow.ai, we're not just embracing the future; we're shaping it.</p><p></p>]]></content:encoded></item></channel></rss>