<?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"><channel><title><![CDATA[Namito’s Clean Code]]></title><description><![CDATA[I write blogs as a notebook for my future self. All of my cool tricks and findings will be recorded here.]]></description><link>https://blogs.namitoyokota.com</link><generator>RSS for Node</generator><lastBuildDate>Tue, 21 Apr 2026 09:29:52 GMT</lastBuildDate><atom:link href="https://blogs.namitoyokota.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Modern React Boilerplate]]></title><description><![CDATA[React is a powerful and flexible library — but that flexibility can be both a blessing and a curse. While it allows developers to build highly performant UIs, the lack of strong opinions often leads to fragmentation and decision fatigue. Starting a n...]]></description><link>https://blogs.namitoyokota.com/modern-react-boilerplate</link><guid isPermaLink="true">https://blogs.namitoyokota.com/modern-react-boilerplate</guid><category><![CDATA[React]]></category><category><![CDATA[vite]]></category><category><![CDATA[react router]]></category><category><![CDATA[react-query]]></category><category><![CDATA[zustand]]></category><category><![CDATA[react-hook-form]]></category><category><![CDATA[zod]]></category><category><![CDATA[Tailwind CSS]]></category><category><![CDATA[motion]]></category><category><![CDATA[framer-motion]]></category><category><![CDATA[date-fns]]></category><category><![CDATA[vitest]]></category><category><![CDATA[eslint]]></category><category><![CDATA[Prettier]]></category><category><![CDATA[husky]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Wed, 14 May 2025 21:07:30 GMT</pubDate><content:encoded><![CDATA[<p><a target="_blank" href="https://react.dev/">React</a> is a powerful and flexible library — but that flexibility can be both a blessing and a curse. While it allows developers to build highly performant UIs, the lack of strong opinions often leads to fragmentation and decision fatigue. Starting a new project from scratch means carefully selecting tools that work well together and scale with your needs.</p>
<p>After researching the current ecosystem, I assembled a modern <strong>React</strong> boilerplate using a thoughtful, balanced tech stack. Here’s a breakdown of each decision, the alternative I considered, and why the chosen solution won out.</p>
<h2 id="heading-build-tool">Build Tool</h2>
<p>A build tool transforms your source code into optimized assets that the browser can run. It handles tasks like bundling JavaScript, compiling TypeScript, processing stylesheets, and enabling hot-reloading during development.</p>
<h3 id="heading-vite">🏆 Vite</h3>
<p><a target="_blank" href="https://vite.dev/">Vite</a> offers lightning-fast startup, hot module replacement, and native ES module support. It's optimized for modern frameworks and minimizes configuration overhead.</p>
<h3 id="heading-webpack">💤 Webpack</h3>
<p><a target="_blank" href="https://webpack.js.org/">Webpack</a> is still powerful and flexible but requires significantly more setup. It’s slower during development and more complex to configure, especially for modern JavaScript workflows.</p>
<hr />
<h2 id="heading-router">Router</h2>
<p>A router controls how different components of your app are displayed based on the URL. It enables navigation between views and supports features like nested routes, redirects, and dynamic parameters.</p>
<h3 id="heading-react-router">🏆 React Router</h3>
<p><a target="_blank" href="https://reactrouter.com/">React Router</a> is a mature, reliable solution with full support for nested routing, dynamic routes, and lazy loading. It’s well-documented and widely used.</p>
<h3 id="heading-tanstack-router">💤 TanStack Router</h3>
<p>While innovative, <a target="_blank" href="https://tanstack.com/router/latest">TanStack Router</a> has less documentation and a smaller user base. Its newer API is promising, but not yet as production-hardened or familiar to most teams.</p>
<hr />
<h2 id="heading-data-fetching">Data Fetching</h2>
<p>Data fetching refers to retrieving data from external sources — usually APIs — and integrating it into your application. This process includes loading states, caching, and synchronization with the UI.</p>
<h3 id="heading-react-query">🏆 React Query</h3>
<p><a target="_blank" href="https://tanstack.com/query/latest/docs/framework/react/overview">React Query</a> simplifies data-fetching logic with built-in caching, background syncing, and query invalidation. It excels at managing server state efficiently and declaratively.</p>
<h3 id="heading-swr">💤 SWR</h3>
<p><a target="_blank" href="https://swr.vercel.app/">SWR</a> is another solid choice but is best suited for simple use cases. It lacks some advanced features like built-in mutation support, query invalidation, and DevTools that <strong>React Query</strong> offers.</p>
<hr />
<h2 id="heading-state-management">State Management</h2>
<p>State management is how your app keeps track of data that changes over time — like UI settings, form inputs, and user actions—and makes it available across components.</p>
<h3 id="heading-zustand">🏆 Zustand</h3>
<p><a target="_blank" href="https://zustand-demo.pmnd.rs/">Zustand</a> is a minimal, flexible state manager with a clean API. It avoids boilerplate and works well alongside React hooks.</p>
<h3 id="heading-redux">💤 Redux</h3>
<p><a target="_blank" href="https://redux.js.org/">Redux</a> remains a robust option for large-scale apps but brings significant complexity and boilerplate. It's better suited for teams already invested in its ecosystem.</p>
<hr />
<h2 id="heading-form-validation">Form Validation</h2>
<p>Form validation ensures that users enter correct and complete information before submitting a form. It helps verify data types, enforce required fields, and give feedback to users.</p>
<h3 id="heading-react-hook-form-zod">🏆 React Hook Form + Zod</h3>
<p><a target="_blank" href="https://react-hook-form.com/">React Hook Form</a> offers performant and scalable form state management. <a target="_blank" href="https://zod.dev/">Zod</a> brings type-safe, schema-based validation that integrates seamlessly.</p>
<h3 id="heading-formik-yup">💤 Formik + Yup</h3>
<p><a target="_blank" href="https://formik.org/">Formik</a> was once the go-to solution, but it incurs more re-renders and has less efficient performance. <a target="_blank" href="https://github.com/jquense/yup">Yup</a> is still a good schema validator but lacks some of <strong>Zod</strong>’s TypeScript integration benefits.</p>
<hr />
<h2 id="heading-styling">Styling</h2>
<p>Styling defines how your app looks — colors, layout, typography, spacing, and responsiveness. The styling approach you choose affects both design flexibility and code maintainability.</p>
<h3 id="heading-tailwind-css">🏆 Tailwind CSS</h3>
<p><a target="_blank" href="https://tailwindcss.com/">Tailwind</a>’s utility-first approach enables rapid UI development without managing global styles or naming conventions. It results in consistent, maintainable styling within components.</p>
<h3 id="heading-css-modules-scss">💤 CSS Modules / SCSS</h3>
<p>These traditional styling methods require more setup and introduce global style management complexities. While effective, they tend to slow down development compared to Tailwind’s approach.</p>
<hr />
<h2 id="heading-authentication">Authentication</h2>
<p>Authentication is the process of verifying a user’s identity and managing their session. It typically involves logging in, storing tokens, and controlling access to protected resources.</p>
<h3 id="heading-react-oidc-context">🏆 react-oidc-context</h3>
<p>This library simplifies <a target="_blank" href="https://auth0.com/docs/authenticate/protocols/openid-connect-protocol">OpenID Connect (OIDC)</a> authentication with built-in support for token handling, login/logout, and secure in-memory storage. It integrates cleanly with <strong>React</strong>’s context model.</p>
<h3 id="heading-auth0-sdk">💤 Auth0 SDK</h3>
<p><a target="_blank" href="https://auth0.com/docs/libraries">Auth0’s SDK</a> is full-featured but tightly coupled to the Auth0 platform, making it less ideal for teams managing their own identity provider or seeking vendor neutrality.</p>
<hr />
<h2 id="heading-animation-library">Animation Library</h2>
<p>An animation library helps you create transitions and effects like fades, slides, and interactive gestures. These animations enhance user experience by making the UI feel dynamic and responsive.</p>
<h3 id="heading-motion">🏆 Motion</h3>
<p><a target="_blank" href="https://motion.dev/">Motion</a> is purpose-built for React, offering declarative animations, gesture support, and physics-based motion. It's beginner-friendly and powerful enough for complex use cases.</p>
<h3 id="heading-gsap">💤 GSAP</h3>
<p><a target="_blank" href="https://gsap.com/">GSAP</a> is an extremely powerful animation engine, but its imperative model doesn't fit as naturally into <strong>React</strong>’s declarative paradigm. It also introduces more complexity for simple transitions.</p>
<hr />
<h2 id="heading-date-management">Date Management</h2>
<p>Date management libraries help you work with dates and times—formatting, parsing, comparing, and manipulating them accurately and efficiently.</p>
<h3 id="heading-date-fns">🏆 date-fns</h3>
<p><a target="_blank" href="https://date-fns.org/">date-fns</a> is a modern, lightweight library with modular utilities for parsing, formatting, and manipulating dates. It works well with modern JavaScript and TypeScript.</p>
<h3 id="heading-momentjs">💤 Moment.js</h3>
<p><a target="_blank" href="https://momentjs.com/">Moment.js</a> is now deprecated and known for being heavy and mutating date objects. It’s no longer recommended for new projects.</p>
<hr />
<h2 id="heading-testing">Testing</h2>
<p>Testing involves writing code that verifies your application works as expected. It includes unit tests, integration tests, and UI tests to prevent bugs and ensure reliability.</p>
<h3 id="heading-vitest">🏆 Vitest</h3>
<p><a target="_blank" href="https://vitest.dev/">Vitest</a> is designed specifically for <strong>Vite</strong> projects. It offers fast test execution, HMR for tests, built-in TypeScript support, and zero-config setup.</p>
<h3 id="heading-jest">💤 Jest</h3>
<p><a target="_blank" href="https://jestjs.io/">Jest</a> is still widely used and powerful, but its slower performance and heavier configuration make it less ideal for Vite-based projects. <strong>Vitest</strong> integrates more naturally with the build environment.</p>
<hr />
<h2 id="heading-clean-code">Clean Code</h2>
<p>Clean code tools automatically format and analyze your code to enforce consistent style and catch potential errors. This ensures a shared standard across the team and improves code quality.</p>
<p>This trio enforces code quality and consistency. <strong>ESLint</strong> catches common issues, <strong>Prettier</strong> handles formatting, and <strong>Husky</strong> runs checks before code is committed.</p>
<h3 id="heading-eslint">🏆 <strong>Eslint</strong></h3>
<p><a target="_blank" href="https://eslint.org/">ESLint</a> is a JavaScript and TypeScript linter that helps enforce consistent code quality and best practices by catching errors, enforcing coding standards, and integrating with modern frameworks. Unlike manual code reviews or relying on editors for syntax errors, <strong>ESLint</strong> provides automated static analysis to prevent bugs early.</p>
<h3 id="heading-prettier">🏆 <strong>Prettier</strong></h3>
<p><a target="_blank" href="https://prettier.io/">Prettier</a> is an opinionated code formatter that automatically formats code for consistency by enforcing style rules like indentation, line wrapping, and spacing. Unlike manual formatting or relying on team conventions, <strong>Prettier</strong> eliminates style debates by ensuring all code follows the same structure.</p>
<h3 id="heading-husky">🏆 <strong>Husky</strong></h3>
<p><a target="_blank" href="https://typicode.github.io/husky/">Husky</a> is a Git hook manager that helps enforce pre-commit and pre-push checks by running scripts like <strong>ESLint</strong>, <strong>Prettier</strong>, or tests before committing code. Unlike relying on manual checks or CI pipelines catching issues later, <strong>Husky</strong> prevents bad code from being committed in the first place.</p>
]]></content:encoded></item><item><title><![CDATA[4 Approaches to hosting SPAs with AWS]]></title><description><![CDATA[Choosing the right hosting strategy for your single-page application (SPA) on AWS can be overwhelming. With services ranging from simple object storage to fully managed container orchestration, AWS offers powerful options. We'll dive into how each wo...]]></description><link>https://blogs.namitoyokota.com/4-approaches-to-hosting-spas-with-aws</link><guid isPermaLink="true">https://blogs.namitoyokota.com/4-approaches-to-hosting-spas-with-aws</guid><category><![CDATA[AWS]]></category><category><![CDATA[spa]]></category><category><![CDATA[React]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[frontend]]></category><category><![CDATA[deployment]]></category><category><![CDATA[hosting]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Thu, 08 May 2025 12:15:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747232489269/bbc0d074-89f0-4e67-99a4-1188a063083b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Choosing the right hosting strategy for your single-page application (SPA) on AWS can be overwhelming. With services ranging from simple object storage to fully managed container orchestration, AWS offers powerful options. We'll dive into how each works, their pros and cons, ease of rollback, and when each is the best fit.</p>
<h2 id="heading-s3-cloudfront">S3 + CloudFront</h2>
<p>Build your frontend and upload the static files to an S3 bucket. CloudFront is configured to distribute these assets globally, with support for SPA routing, custom error handling, and cache control. Builds can be versioned by directory (e.g. <code>/v1.3.2/</code>) and served by changing CloudFront origin settings or rewrites.</p>
<h3 id="heading-pros">Pros:</h3>
<ul>
<li><p>Low cost, scalable, and reliable.</p>
</li>
<li><p>Global performance via CloudFront’s CDN.</p>
</li>
<li><p>Easy rollbacks by switching directory paths or aliases.</p>
</li>
<li><p>Full control over cache headers, security, and routing.</p>
</li>
<li><p>Easily scriptable with CI tools.</p>
</li>
</ul>
<h3 id="heading-cons">Cons:</h3>
<ul>
<li><p>Initial setup takes effort.</p>
</li>
<li><p>Must handle deployments and cache invalidation yourself.</p>
</li>
<li><p>No built-in CI/CD previews.</p>
</li>
</ul>
<p>This approach is ideal for production-grade applications, especially in enterprise environments where performance, control, and cost optimization matter. It works well for static SPAs, marketing sites, or internal portals requiring strict cache policies, SPA routing, and versioning. Teams that prefer custom pipelines and infra-as-code love this model for its flexibility.</p>
<h2 id="heading-amplify">Amplify</h2>
<p>Amplify Hosting is a fully managed CI/CD + hosting solution for frontend apps. Once your Git repository is connected, Amplify builds and deploys automatically on each commit. It includes global CDN, HTTPS, branch-based preview deployments, custom domain setup, and support for all major frontend frameworks. Amplify handles deployment infrastructure behind the scenes.</p>
<h3 id="heading-pros-1">Pros:</h3>
<ul>
<li><p>Very fast to get started.</p>
</li>
<li><p>Built-in CI/CD with preview branches.</p>
</li>
<li><p>Built-in HTTPS, SPA routing, and hosting via CDN.</p>
</li>
<li><p>Good integration with other Amplify services.</p>
</li>
</ul>
<h3 id="heading-cons-1">Cons:</h3>
<ul>
<li><p>Less control over infrastructure and caching behavior.</p>
</li>
<li><p>Harder to integrate into custom versioning or rollback strategies.</p>
</li>
<li><p>Preview builds and multiple branches can increase cost quickly.</p>
</li>
</ul>
<p>Amplify is a great fit for startups, prototypes, MVPs, hackathons, or any project where speed, simplicity, and quick feedback matter. It’s excellent for smaller teams or solo developers who don’t want to manage infrastructure. It's also useful during early product development when CI/CD and preview environments offer high velocity.</p>
<h2 id="heading-ecs-ec2fargate">ECS + EC2/Fargate</h2>
<p>You package your frontend build into a Docker image (usually with NGINX to serve static files) and deploy it using ECS. With Fargate, AWS manages the compute; with EC2 launch type, you manage the servers. You define task definitions, services, and optionally use Application Load Balancers or CloudFront for distribution. You roll back by deploying an older Docker image or version-tagged container.</p>
<h3 id="heading-pros-2">Pros:</h3>
<ul>
<li><p>High control over web server behavior, headers, and routing logic.</p>
</li>
<li><p>Suitable for containerized infrastructure alongside other services.</p>
</li>
<li><p>Works well with CI/CD pipelines and infrastructure as code.</p>
</li>
<li><p>Rollback is easy by re-deploying previous container versions.</p>
</li>
</ul>
<h3 id="heading-cons-2">Cons:</h3>
<ul>
<li><p>Higher complexity — requires Docker knowledge and ECS familiarity.</p>
</li>
<li><p>Not cost-efficient for purely static apps (more infra than needed).</p>
</li>
<li><p>Slower to set up and deploy compared to Amplify or S3.</p>
</li>
</ul>
<p>This approach is ideal for larger, containerized applications where frontend and backend are tightly integrated and deployed together. It's commonly used by teams with DevOps maturity, especially when using ECS for the backend and wanting unified infrastructure. It's a strong choice when advanced routing, custom headers, or NGINX tweaks are needed, but overkill for simple static SPAs.</p>
<h2 id="heading-ec2">EC2</h2>
<p>This is a traditional approach where you provision one or more EC2 instances, configure an OS-level web server (like NGINX or Apache), and serve your built frontend app from the instance. You might set up an Elastic Load Balancer (ELB) or integrate with CloudFront for CDN support. Deployments typically involve copying build files via SSH or through automated CI/CD scripts.</p>
<h3 id="heading-pros-3">Pros:</h3>
<ul>
<li><p>Full control over the hosting environment (OS, web server config).</p>
</li>
<li><p>Works well for legacy setups or when deep customization is needed.</p>
</li>
<li><p>Easy to host multiple apps or custom backends on the same server.</p>
</li>
</ul>
<h3 id="heading-cons-3">Cons:</h3>
<ul>
<li><p>High maintenance — must patch, scale, and monitor servers yourself.</p>
</li>
<li><p>Slower deployments unless automation is set up.</p>
</li>
<li><p>Can be costly and less efficient for static frontends.</p>
</li>
</ul>
<p>Hosting SPAs on EC2 makes sense in legacy environments or when your team is already managing EC2 infrastructure and wants tight OS-level control. It’s also a fit for highly customized web servers or setups where containerization isn't yet adopted. However, for new projects, it’s generally recommended to prefer Fargate or static hosting models.</p>
]]></content:encoded></item><item><title><![CDATA[Microsoft Azure doesn’t like your IPv6 address]]></title><description><![CDATA[When setting up a new machine after a company acquisition, I ran into several strange errors connecting with Azure DevOps. If any of the following sound familiar, keep reading:

Azure DevOps' Personal Access Tokens page shows error: TF400893: Unable ...]]></description><link>https://blogs.namitoyokota.com/microsoft-azure-doesnt-like-your-ipv6-address</link><guid isPermaLink="true">https://blogs.namitoyokota.com/microsoft-azure-doesnt-like-your-ipv6-address</guid><category><![CDATA[azure-devops]]></category><category><![CDATA[Azure]]></category><category><![CDATA[IPv4]]></category><category><![CDATA[ipv6]]></category><category><![CDATA[Solved]]></category><category><![CDATA[git clone]]></category><category><![CDATA[Git]]></category><category><![CDATA[debugging]]></category><category><![CDATA[troubleshooting]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Thu, 01 May 2025 15:38:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747232515491/d125bea2-b5fa-415c-8e6f-fdaf30acdd69.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When setting up a new machine after a company acquisition, I ran into several strange errors connecting with <a target="_blank" href="https://learn.microsoft.com/en-us/azure/devops/user-guide/what-is-azure-devops?view=azure-devops">Azure DevOps</a>. If any of the following sound familiar, keep reading:</p>
<ul>
<li><p><a target="_blank" href="https://venminder.visualstudio.com/_usersSettings/tokens">Azure DevOps' Personal Access Tokens page</a> shows error: <code>TF400893: Unable to contact the server. Please check your network connection and try again.</code></p>
</li>
<li><p><a target="_blank" href="https://gets-3-rsd.venminder.com/diagnostics/index.html">Visual Studio’s Connect to a Project</a> dialog shows no repositories.</p>
</li>
<li><p><a target="_blank" href="https://git-scm.com/docs/git-clone">Visual Studio’s authentication</a> fails with error: <code>We could not refresh the credentials for the account "..." The SSL connection could not be established, see inner exception.</code></p>
</li>
<li><p>Visual Studio pops up the <a target="_blank" href="https://gets-3-rsd.venminder.com/diagnostics/index.html">“Let’s get you signed in”</a> dialog in a infinite loop.</p>
</li>
<li><p><a target="_blank" href="https://gets-3-rsd.venminder.com/diagnostics/index.html">Visual Studio’s account icon</a> does not show profile image.</p>
</li>
<li><p><a target="_blank" href="https://git-scm.com/docs/git-clone">Cloning repository from the command line</a> shows error:</p>
<pre><code class="lang-plaintext">  fatal: An error occured while sending the request.
  fatal: The underlying connection was closed: An unexpected error occured on a send.
  fatal: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
  fatal: An existing connection was forcibly closed by the remote host.
  fatal: Authentication failed for '...'
</code></pre>
</li>
</ul>
<h2 id="heading-solution">Solution</h2>
<p>Long story short, this can be resolved by turning off the IPv6 adapter on your machine. If you are on Windows, follow these steps:</p>
<ol>
<li><p>Go to the <code>Control Panel</code> → <code>Network and Internet</code>.</p>
</li>
<li><p>Select <code>Network and Sharing Center</code> → <code>Change adapter settings</code>.</p>
</li>
<li><p>Right click on your active adapter → <code>Properties</code>.</p>
</li>
<li><p>Uncheck <code>Internet Protocol Version 6 (TCP/IPv6)</code>.</p>
</li>
<li><p>Click <code>Ok</code>.</p>
</li>
</ol>
<p>If you are using another operating system, use <a target="_blank" href="https://support.strongvpn.com/hc/en-us/articles/360026848373-How-To-Disable-IPv6-on-Various-Operating-Systems">this guide to disable IPv6</a>.</p>
<p>If you prefer to keep using the IPv6, you can alternatively disable IPv6 specifically for <a target="_blank" href="http://dev.azure.com"><code>dev.azure.com</code></a> URL by editing the hosts file.</p>
<ol>
<li><p>In the <code>File Explorer</code>, navigate to <code>C:\\Windows\\System32\\drivers\\etc\\hosts</code>.</p>
</li>
<li><p>Add a new line at the bottom of the file: <code>13.107.42.20 dev.azure.com</code></p>
</li>
</ol>
<h2 id="heading-ipv4-and-ipv6">IPv4 and IPv6</h2>
<p>IPv4 (Internet Protocol version 4) is the foundation of most internet traffic today. It uses 32-bit addresses, which allows for about 4.3 billion unique IP addresses — once thought to be more than enough. But as the internet grew, we quickly ran out of available IPv4 addresses. To solve this, IPv6 was developed. IPv6 uses 128-bit addresses, offering an enormous address space (3.4 × 10^38 possible addresses) and includes modern networking features like simplified routing and improved security.</p>
<p>Despite being introduced in the late 1990s, IPv6 adoption has been slow — especially in enterprise environments. Many internal systems, corporate firewalls, VPNs, and even cloud-based tools are still built with IPv4 as the default. Microsoft services like Azure DevOps and Visual Studio, for example, still exhibit spotty or incomplete support for IPv6. In some cases, applications will attempt to use IPv6 first, but fail to connect or time out silently. Without proper fallback to IPv4, this results in broken authentication, clone failures, or unresponsive UIs.</p>
<h2 id="heading-further-reading">Further reading</h2>
<ul>
<li><p><a target="_blank" href="https://docs.anchorpoint.app/docs/version-control/troubleshooting/azure-devops/">Troubleshooting Azure DevOps by Anchorpoint</a>.</p>
</li>
<li><p><a target="_blank" href="https://support.strongvpn.com/hc/en-us/articles/360026848373-How-To-Disable-IPv6-on-Various-Operating-Systems">How To Disable IPv6 on Various Operating Systems?</a></p>
</li>
<li><p><a target="_blank" href="https://stackoverflow.com/questions/67230241/fatal-unable-to-access-https-dev-azure-com-xxx-openssl-ssl-connect-connec/68259166#68259166">Stack Overflow answers for fatal connection error with Azure DevOps</a>.</p>
</li>
<li><p><a target="_blank" href="https://www.quora.com/Why-is-IPv6-not-widely-used-in-todays-Internet">Why is IPv6 not widely used in today’s Internet?</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Creating a client-side diagnostics site]]></title><description><![CDATA[Debugging issues with clients of an enterprise software solution often feels like chasing the wind. Your team release a new feature and receive great feedback from many customers except one: reports missing icons, broken layouts, or the entire page n...]]></description><link>https://blogs.namitoyokota.com/creating-a-client-side-diagnostics-site</link><guid isPermaLink="true">https://blogs.namitoyokota.com/creating-a-client-side-diagnostics-site</guid><category><![CDATA[Security]]></category><category><![CDATA[client]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Static Website]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Mon, 28 Apr 2025 16:58:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1747232281417/b0d7b701-0ea4-4c97-ac88-b16ea4040596.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Debugging issues with clients of an enterprise software solution often feels like chasing the wind. Your team release a new feature and receive great feedback from many customers except one: reports missing icons, broken layouts, or the entire page not loading. The culprit for my scenario was an overzealous firewall or content filter silently blocking third-party resources. After spending a week going back and forth with IT (with the client as the middle man), I decided to build a simple, <strong>client-side diagnostics page</strong> to check which URLs are blocked and help IT teams know exactly what needs to be whitelisted.</p>
<h2 id="heading-acceptance-criteria">Acceptance Criteria</h2>
<p>Before brainstorming solutions, let’s first set some ground rules:</p>
<ul>
<li><p><strong>Client-Side</strong>: The page must be fully static and run entirely in the browser — no backend, no server-side logic. This ensures it’s easy to host anywhere and works in restrictive environments.</p>
</li>
<li><p><strong>Simple Deployment</strong>: There should be no build process or bundling step required. Just pure HTML, CSS, and vanilla JavaScript — drop the files into a server and it should just work.</p>
</li>
<li><p><strong>Maintainable</strong>: While the ideal setup would involve fetching the list of resources from an external API, the initial implementation can use a hardcoded array of URLs. This keeps the MVP simple and testable.</p>
</li>
<li><p><strong>Reporting</strong>: For each URL, the tool should clearly and accurate indicate whether it is accessible. The status must be visually obvious (e.g., ✅, ❌, ⏳).</p>
</li>
<li><p><strong>Secure</strong>: Any method used to check URLs must not interfere with the styling, behavior, or security of the page itself. This includes isolating loaded scripts or styles to avoid accidental side effects.</p>
</li>
</ul>
<h2 id="heading-3-possible-approaches">3 Possible Approaches</h2>
<h3 id="heading-1-fetch">1. fetch()</h3>
<p>The <code>fetch()</code> approach is a straightforward way to check if a URL is reachable, but its behavior depends on CORS settings. With standard <code>fetch()</code>, the browser requires the server to allow cross-origin requests via CORS headers; if not, the request will fail—even if the URL is actually reachable. To work around this, using <code>fetch()</code> with <code>mode: 'no-cors'</code> lets the request go through silently without needing CORS approval. While the response is opaque and doesn’t give detailed status codes, it still indicates whether the resource was blocked entirely or not. This makes the <code>no-cors</code> method a practical choice for checking basic reachability across different types of assets.</p>
<h3 id="heading-2-dom-injection">2. DOM Injection</h3>
<p>The DOM injection approach works by dynamically adding <code>&lt;script&gt;</code>, <code>&lt;link&gt;</code>, or <code>&lt;img&gt;</code> elements to the page and watching for their <code>onload</code> or <code>onerror</code> events. If the resource loads successfully, it’s likely not blocked; if it fails, the browser will fire an error event, signaling that it might be blocked by a firewall or content filter. This method gives a more accurate picture of whether the resource can actually be fetched and used by the browser. It's especially useful for fonts, stylesheets, and JavaScript files, though care must be taken to avoid interfering with the existing page layout or behavior.</p>
<h3 id="heading-3-using-ltiframegt">3. Using &lt;iframe&gt;</h3>
<p>The <code>&lt;iframe&gt;</code> approach involves embedding an external URL inside a hidden or sandboxed iframe and observing whether it loads successfully. If the iframe triggers a load event, the resource is likely accessible; if not, it may be blocked. While this method can detect general reachability, it’s less precise for specific assets like fonts or scripts. It’s best used for checking full websites or dashboards rather than individual files. Additionally, many sites block iframe embedding using headers like <code>X-Frame-Options</code>, which can limit its effectiveness.</p>
<h2 id="heading-implementation">Implementation</h2>
<p>To keep things lightweight and avoid CORS headaches, I chose to implement the diagnostics page using the <code>fetch()</code> API with <code>mode: 'no-cors'</code>. This approach doesn't give you access to the actual response content or status code, but it <em>does</em> let you know whether the browser was able to reach the resource at all—which is perfect for detecting firewall blocks. For each URL I want to check, I make a <code>HEAD</code> request in <code>no-cors</code> mode, and if the request completes without throwing an error, I consider that a success. While the response object is opaque and always returns <code>ok: false</code>, the real signal is whether the <code>.catch()</code> block is triggered. If it throws, the resource is most likely blocked; if it doesn't, the URL is accessible.</p>
<p>This approach lets the diagnostics tool focus purely on <strong>reachability</strong>, which is usually what matters when dealing with IT departments and URL whitelisting. I wrapped each check in a small promise and updated the UI with a status icon: a green check for success, a red “x” for failure, and a spinner while the check is in progress. Since the diagnostics page is entirely client-side, there are no privacy concerns, no server logs, and no CORS configuration required. It works from any browser and doesn’t require installation — just load the page and instantly see which URLs are blocked. This approach gave me the right balance of simplicity, reliability, and ease of deployment.</p>
<p>This is the heart of the logic, using <code>fetch()</code> in <code>no-cors</code> mode:</p>
<pre><code class="lang-jsx"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">checkUrlAccessibility</span>(<span class="hljs-params">url</span>) </span>{
  <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve</span>) =&gt;</span> {
    fetch(url, {
      <span class="hljs-attr">method</span>: <span class="hljs-string">'HEAD'</span>,
      <span class="hljs-attr">mode</span>: <span class="hljs-string">'no-cors'</span>,
    })
      .then(<span class="hljs-function">() =&gt;</span> resolve(<span class="hljs-literal">true</span>))
      .catch(<span class="hljs-function">() =&gt;</span> resolve(<span class="hljs-literal">false</span>));
  });
}
</code></pre>
<p>Looping through an array of resources to check each one and update the UI accordingly:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> resources = [
  { <span class="hljs-attr">name</span>: <span class="hljs-string">'Google Fonts'</span>, <span class="hljs-attr">url</span>: <span class="hljs-string">'...'</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">'Font Awesome'</span>, <span class="hljs-attr">url</span>: <span class="hljs-string">'...'</span> },
  { <span class="hljs-attr">name</span>: <span class="hljs-string">'Bootstrap'</span>, <span class="hljs-attr">url</span>: <span class="hljs-string">'...'</span> }
];

resources.forEach(<span class="hljs-function"><span class="hljs-params">resource</span> =&gt;</span> {
  showLoadingIcon(resource.name);
  checkUrlAccessibility(resource.url).then(<span class="hljs-function"><span class="hljs-params">isAccessible</span> =&gt;</span> {
    updateStatusIcon(resource.name, isAccessible);
  });
});
</code></pre>
<h2 id="heading-testing">Testing</h2>
<p>To test whether the diagnostics page correctly detected blocked resources, there are a few simple options — such as using intentionally breaking URLs, using a browser extension, or modifying the <code>hosts</code> file to simulate a DNS failure. All of these approaches are easy ways to trigger errors without requiring a significant time to set up.</p>
<p>However, the best approach I found was to use the browser’s DevTools. By manually <a target="_blank" href="https://developer.chrome.com/docs/devtools/network-request-blocking">blocking specific domains in the Network tab</a>, I could mimic a client's firewall filtering out resources. This allowed me to confirm that the diagnostics page correctly showed failures without needing to set up a real firewall or proxy. With everything working as expected, the tool was ready to hand off to client IT teams for real-world testing.</p>
]]></content:encoded></item><item><title><![CDATA[Monitoring user interactions with DataDog RUM]]></title><description><![CDATA[Objective
We recently implemented a data export feature that allows users to retrieve specific reports by selecting an option via radio buttons. To assess the feature's adoption and understand user preferences, we needed a way to track how often user...]]></description><link>https://blogs.namitoyokota.com/monitoring-user-interactions-with-datadog-rum</link><guid isPermaLink="true">https://blogs.namitoyokota.com/monitoring-user-interactions-with-datadog-rum</guid><category><![CDATA[user monitoring]]></category><category><![CDATA[Datadog]]></category><category><![CDATA[rum ]]></category><category><![CDATA[monitoring]]></category><category><![CDATA[metrics]]></category><category><![CDATA[Metrics Tracking]]></category><category><![CDATA[user experience]]></category><category><![CDATA[User Interface]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Wed, 05 Mar 2025 16:48:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489632434/8f7c5946-c30d-4606-bc6f-a53b43c4936e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-objective">Objective</h2>
<p>We recently implemented a data export feature that allows users to retrieve specific reports by selecting an option via radio buttons. To assess the feature's adoption and understand user preferences, we needed a way to track how often users initiate an export and which report types are being requested most frequently. After evaluating different solutions, we chose <strong>DataDog Real User Monitoring (RUM)</strong>.</p>
<h2 id="heading-what-is-datadog">What is DataDog?</h2>
<p><strong>Datadog</strong> is an observability platform that supports every phase of software development on any stack. The platform consists of many products that help you build, test, monitor, debug, optimize, and secure your software. These products can be used individually or combined into a customized solution.</p>
<h2 id="heading-what-is-datadog-rum">What is DataDog RUM?</h2>
<p><strong>DataDog Real User Monitoring (RUM)</strong> provides deep insight into your application’s frontend performance. Monitor real user data to optimize your web experience and provide exceptional user experiences. Correlate synthetic tests, backend metrics, traces, and logs in a single place to identify and troubleshoot performance issues across the stack.</p>
<p>With the Datadog RUM Browser SDK, you can also:</p>
<ul>
<li><p>Monitor your application’s pageviews and performance to investigate performance issues.</p>
</li>
<li><p>Gain complete, end-to-end visibility into resources and requests (such as images, CSS files, JavaScript assets, and font files).</p>
</li>
<li><p>Automatically collect and monitor any interesting events with all relevant context, and manually collect errors that aren’t automatically tracked.</p>
</li>
<li><p>Track user interactions that were performed during a user journey so you can get insight into user behavior while meeting privacy requirements.</p>
</li>
<li><p>Surface user pain points with frustration signals.</p>
</li>
<li><p>Pinpoint the cause of an error down to the line of code to resolve it.</p>
</li>
</ul>
<h2 id="heading-cost">Cost</h2>
<p><a target="_blank" href="https://www.datadoghq.com/pricing/?product=real-user-monitoring--session-replay#products">DataDog RUM pricing</a> is <strong>based on session volume</strong>, meaning you pay for each user session that interacts with your application. A session typically starts when a user loads a page and ends after <strong>15 minutes of inactivity</strong>. <strong>Basic RUM</strong> starts at $1.50 per 1,000 sessions. <strong>RUM with Session Replay</strong> starts at $1.80 per 1,000 sessions.</p>
<h2 id="heading-alternative-solution">Alternative solution</h2>
<p>If your company will not pay for DataDog RUM, <strong>Log Management (Log Collection)</strong> can serve as a viable alternative for tracking user interactions and frontend performance. While RUM is built for real user monitoring, logs can be structured to capture similar data points with added flexibility.</p>
<p>The main 3 difference from RUM and Log Management are:</p>
<ol>
<li><p>Log Management does not monitor user interactions. It is a backend-driven logging system; therefore, requires an API request from the frontend.</p>
</li>
<li><p>Log Management requires more configurations as its intended use is wide and provides more control.</p>
</li>
<li><p><a target="_blank" href="https://www.datadoghq.com/pricing/?product=log-management#products">Log Management will likely be cheaper</a>, although this varies on the number of logs compared to the number of sessions.</p>
</li>
</ol>
<h2 id="heading-implementation">Implementation</h2>
<p>All of the code snippets below use the <strong>Aurelia framework</strong>, so depending on a library/framework you’re using, the implementation can vary minorly.</p>
<h3 id="heading-1-install-the-npm-package">1. Install the npm package</h3>
<p>To use the <a target="_blank" href="https://github.com/DataDog/browser-sdk#readme">DataDog Browser SDK</a>, install the following npm package: <code>npm i @datadog/browser-rum</code>. At the time of this writing, the latest package version is <code>6.4.0</code> with a bundle size of <code>59.5 kB (gzip)</code> .</p>
<h3 id="heading-2-add-a-new-application-in-the-datadog-dashboard">2. Add a new application in the DataDog dashboard</h3>
<p>In Datadog, navigate to the <a target="_blank" href="https://app.datadoghq.com/rum/list">Digital Experience &gt; Add an Application</a> page and select the JavaScript (JS) application type.</p>
<h3 id="heading-3-create-a-new-service-in-the-frontend">3. Create a new service in the frontend</h3>
<p>The <code>readonly rumConfig</code> object should be copied and pasted from the DataDog dashboard.</p>
<pre><code class="lang-tsx">import { datadogRum } from '@datadog/browser-rum';
import appSettings from '../../config/appsettings.json';
import packageInfo from '../../package.json';

export class MonitoringService {
  /** Application configurations */
  readonly rumConfig = {
    applicationId: '{{APPLICATOIN_ID}}',
    clientToken: '{{CLIENT_TOKEN}}',
    site: 'datadoghq.com',
    service: '{{SERVICE}}',
    env: appSettings .environment,
    version: packageInfo.version,
    sessionSampleRate: 100,
    sessionReplaySampleRate: 20,
    defaultPrivacyLevel: 'mask-user-input',
  } as RumInitConfiguration;

  constructor() {}

  /**
   * Initializes RUM browser SDK
   */
  initialize(): void {
    datadogRum.init(this.rumConfig);
  }
}
</code></pre>
<p>It is valuable here that the <code>environment</code> and the <code>versio</code>n is dynamic. For our case, I retrieved the environment from client side app settings, and the versioning number from the <code>package.json</code> file.</p>
<h3 id="heading-4-initialize-datadog-rum-sdk-on-site-load">4. Initialize DataDog RUM SDK on site load</h3>
<p>Wherever the root page load logic lives, for us is in the <code>activate</code> method of <code>app.ts</code> , inject the newly created service, then call the <code>initialize()</code> method:</p>
<pre><code class="lang-tsx">constructor(
  @inject(MonitoringService) private monitoringService: MonitoringService,
) {}

/**
 * Activate lifecycle hook
 */
async activate(): Promise&lt;void&gt; {
  this.monitoringService.initialize();
}
</code></pre>
<h3 id="heading-5-add-a-method-for-logging-a-custom-action">5. Add a method for logging a custom action</h3>
<p>Now that we’ve initialized the RUM SDK, all of the built-in features can be viewed in the dashboard. To fulfill the requirement however, we can add a new method in the <code>MonitoringService</code> class:</p>
<pre><code class="lang-tsx">/**
 * Logs a custom user interaction action
 * @param actionName Unique action name
 * @param additionalInfo Additional data to include in the metric
 */
logCustomMetric(actionName: ActionName, additionalInfo: object): void {
  datadogRum.addAction(actionName, {
    timestamp: new Date().toISOString(),
    ...additionalInfo,
  });
}
</code></pre>
<p>Using an <code>enum</code> for the <code>metricName</code> here is key in order to prevent duplicate names from being used.</p>
<pre><code class="lang-tsx">/**
 * List of action names used for DataDog RUM's custom metrics
 */
export enum ActionName {
    DownloadAssessment = 'download_assessment',
}
</code></pre>
<h3 id="heading-6-call-method-from-the-component-file">6. Call method from the component file</h3>
<p>Finally, we are complete with the service implementation. We are able to call the <code>logCustomMetric()</code> method from anywhere in the application to track any user interaction. Here is an example of a component TypeScript file, triggering a button press to download an assessment deliverable:</p>
<pre><code class="lang-tsx">constructor(
  @inject(MonitoringService) private monitoringService: MonitoringService,
) {}

/**
 * Downloads PDF deliverable of the assessment
 */
downloadAssessment(): void {
  this.canDownloadAssessment = false;
  this.monitoringService.logCustomMetric(
    MetricName.DownloadAssessment,
    {
      pageName: 'PerformReview',
      fileType: 'PDF',
    },
  );

  this.pdfService
    .downloadPdf(this.assessmentId)
      .then((file) =&gt; {
        if (file) {
          this.fileService.downloadFile(file.fileDownloadName, file.contentType, file.fileContents);
        }
      })
      .finally(() =&gt; (this.canDownloadAssessment = true));
}
</code></pre>
<h2 id="heading-result">Result</h2>
<p>View the dashboard!</p>
<p><img src="https://datadog-docs.imgix.net/images/real_user_monitoring/guide/send-custom-user-actions/custom-action-analytics.f44305a5e9ed687ad6428886b5cc5f18.png?fit=max&amp;auto=format&amp;w=1278&amp;h=1276" alt /></p>
<h2 id="heading-security-concerns">Security concerns</h2>
<p>Storing <code>applicationId</code> and <code>clientToken</code> in JavaScript feels like a security vulnerability considering a user can easily retrieve it using Developer Tools. However, these values are intended to be stored in the browser’s JavaScript, similar to Google Analytics tool.</p>
<p>The following reasons are why it is safe to keep the strings in the client side:</p>
<ol>
<li><p>The <code>applicationId</code> and <code>clientToken</code> are used to identify which account or project the data belongs to, not to authenticate users or provide access to private systems.</p>
</li>
<li><p>These tokens only allow data to be sent to the monitoring service. Even if someone extracts them from the browser, all they can do is send fake analytics data—they can’t steal or view any sensitive information from your system.</p>
</li>
<li><p>DataDog RUM has built-in protections against spam or misuse, such as:</p>
<ul>
<li><p>Rate limiting (to prevent excessive requests).</p>
</li>
<li><p>Domain whitelisting (so data is only accepted from approved websites).</p>
</li>
<li><p>Filtering and validation (to detect and ignore invalid or manipulated data</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-ad-blockers-and-vpns">Ad Blockers and VPNs</h2>
<p>From my testing, using the <strong>uBlock Origin</strong> browser extension (with over 39 million users) led to a DataDog SDK initialization failure. Ad blockers and VPNs can interfere with RUM tracking by:</p>
<ul>
<li><p>Blocking requests to DataDog’s RUM endpoints (e.g., <a target="_blank" href="http://datadoghq.com">datadoghq.com</a>).</p>
</li>
<li><p>Preventing the RUM SDK from initializing in the browser.</p>
</li>
<li><p>Hiding or altering IP addresses, reducing geolocation accuracy.</p>
</li>
</ul>
<p>The necessity for implementing a work around here is subjective. We need to know how important this monitoring tool is, how many users are affected, and how difficult it is to implement a work around. If desired however, <strong>a few potential solutions</strong> can be considered:</p>
<ol>
<li><p>If the RUM SDK fails to initialize, use a custom logging solution as a backup. For example, an API request to log the error message from the server.</p>
</li>
<li><p>Implement a script to check if RUM has successfully initialized. If it fails, log the failure internally or notify users with a non-intrusive message suggesting they whitelist the site.</p>
</li>
</ol>
<h2 id="heading-additional-readings">Additional readings</h2>
<p>Many of the content in this writing is a direct quote or summaries from the following resources:</p>
<ul>
<li><p><a target="_blank" href="https://docs.datadoghq.com/getting_started/">DataDog - Getting Started Documentation</a>.</p>
</li>
<li><p><a target="_blank" href="https://docs.datadoghq.com/real_user_monitoring/browser/">DataDog Docs - RUM Browser Monitoring</a>.</p>
</li>
<li><p><a target="_blank" href="https://docs.datadoghq.com/real_user_monitoring/guide/send-rum-custom-actions/?tab=npm">DataDog Docs - Send RUM Custom Actions</a>.</p>
</li>
<li><p><a target="_blank" href="https://youtu.be/OvTLPg0P75s?si=cfK04nCz4pD4Cioh">YouTube - Introduction to RUM &amp; Session Replay</a>.</p>
</li>
<li><p><a target="_blank" href="https://youtu.be/_4kGVvgaf5Q?si=DJX8aVlWzSww0c0-">YouTube - Real User Monitoring by DataDog</a>.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[My goals for 2025]]></title><description><![CDATA[Below is the result of a collaboration between my team lead and myself, on how to grow as a software engineer in 2025.
Team work
The following highlights essential practices for building effective teamwork and collaboration.

Create healthy conflict....]]></description><link>https://blogs.namitoyokota.com/my-goals-for-2025</link><guid isPermaLink="true">https://blogs.namitoyokota.com/my-goals-for-2025</guid><category><![CDATA[teamwork]]></category><category><![CDATA[#growth]]></category><category><![CDATA[learning]]></category><category><![CDATA[Career]]></category><category><![CDATA[career advice]]></category><category><![CDATA[careers]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Sun, 09 Feb 2025 19:09:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489652115/0a3984aa-891c-4003-a4ba-2e079cd7f5d7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Below is the result of a collaboration between my team lead and myself, on how to grow as a software engineer in 2025.</p>
<h2 id="heading-team-work">Team work</h2>
<p>The following highlights essential practices for building effective teamwork and collaboration.</p>
<ul>
<li><p>Create healthy conflict.</p>
<ul>
<li><p>Azure DevOps comments per pull request review metric.</p>
</li>
<li><p>Jira comments per story.</p>
</li>
</ul>
</li>
<li><p>Promote innovation.</p>
<ul>
<li><p>Contribute to lunch &amp; learn opportunities.</p>
</li>
<li><p>Bi-weekly professional develompent time.</p>
</li>
</ul>
</li>
<li><p>Mentorship.</p>
<ul>
<li><p>Meet with full-stack developer bi-weekly to teach frontend topics.</p>
</li>
<li><p>Meet with QA engineer bi-weekly to teach TypeScript and web concepts.</p>
</li>
</ul>
</li>
<li><p>Provide substantial feedback to the broader organization.</p>
<ul>
<li><p>Push accessibility across all products.</p>
</li>
<li><p>Set automated frontend coding standard checks.</p>
</li>
</ul>
</li>
<li><p>Drive collaboration to decision making.</p>
<ul>
<li><p>Leads design/architecture discussions.</p>
</li>
<li><p>Effectively create design diagrams: <a target="_blank" href="https://excalidraw.com/">Excalidraw</a>, <a target="_blank" href="https://markmap.js.org/">markmap</a>.</p>
</li>
<li><p>Hold and lead brainstorming sessions using the silent meeting approach.</p>
</li>
<li><p>Learn to create accurate and detailed sequence diagrams.</p>
</li>
</ul>
</li>
<li><p>Actively look for and address tech debt.</p>
<ul>
<li><p>Jira metrics on tech debt stories created.</p>
</li>
<li><p>Jira metrics on tech debt stories completed.</p>
</li>
</ul>
</li>
<li><p>Become exceptional at problem diagnostics.</p>
<ul>
<li><p>Debug distributed systems.</p>
</li>
<li><p>Automatically detect perform degradation.</p>
</li>
<li><p>Altering pipeline library/steps.</p>
</li>
</ul>
</li>
<li><p>Evangelize.</p>
<ul>
<li><p><a target="_blank" href="https://blogs.namitoyokota.com/">Document learnings into blogs</a>.</p>
</li>
<li><p>Join hackathons/D3 events.</p>
</li>
<li><p>Attend local meet ups.</p>
</li>
</ul>
</li>
</ul>
<h2 id="heading-learning">Learning</h2>
<p>In order to grow as a full-stack developer, learning new technologies and gaining deeper understanding of technologies that I currently use will be key.</p>
<ul>
<li><p>Database Management.</p>
<ul>
<li><p>RDBMS - <a target="_blank" href="https://www.coursera.org/learn/introduction-to-relational-databases">Introduction to Relational Databases</a>.</p>
</li>
<li><p>PGSQL - <a target="_blank" href="https://youtu.be/qw--VYLpxG4?si=eAYctdyWyGuSGXfl">Learn PostgreSQL Tutorial</a>.</p>
</li>
<li><p>Liquibase - <a target="_blank" href="https://learn.liquibase.com/catalog/info/id:152">Liquibase University</a>.</p>
</li>
<li><p>DataGrip - <a target="_blank" href="https://youtu.be/U5SOD-eeK50?si=XZdmH3hYegmYEVJa">DataGrip Overview</a>.</p>
</li>
<li><p>DataDog - <a target="_blank" href="https://learn.datadoghq.com/courses/dd-101-dev">DataDog 101</a>.</p>
</li>
<li><p>TSQL - <a target="_blank" href="https://www.tutorialspoint.com/t_sql/index.htm">TSQL Tutorial</a>.</p>
</li>
<li><p>Other topics.</p>
<ul>
<li><p><a target="_blank" href="https://servebolt.com/articles/profiling-sql-queries/">How to Profile SQL Queries for Better Performance</a>.</p>
</li>
<li><p><a target="_blank" href="https://medium.com/scopedev/introduction-to-profiling-and-optimizing-sql-queries-for-software-engineers-3cf376ecc712">Introduction to Profiling and Optimizing SQL Queries for Software Engineers</a>.</p>
</li>
<li><p><a target="_blank" href="https://learn.microsoft.com/en-us/sql/relational-databases/indexes/clustered-and-nonclustered-indexes-described?view=sql-server-ver16">Clustered vs non-clustered indexes</a>.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>Object Oriented Programming.</p>
<ul>
<li><p>SOLID - <a target="_blank" href="https://www.udemy.com/course/solid-design/">SOLID Principles: Introducing Software Architecture &amp; Design</a>.</p>
</li>
<li><p>LINQ - <a target="_blank" href="https://www.codecademy.com/learn/learn-c-sharp-lists-and-linq">Learn C#: Lists and LINQ</a>.</p>
</li>
<li><p>Design Patterns - <a target="_blank" href="https://refactoring.guru/design-patterns">Refactoring Guru</a>.</p>
</li>
<li><p>CQRS - <a target="_blank" href="https://udidahan.com/2009/12/09/clarified-cqrs/">Clarified CQRS</a>.</p>
</li>
</ul>
</li>
<li><p>Frontend.</p>
<ul>
<li><p>React.</p>
<ul>
<li><p><a target="_blank" href="https://www.coursera.org/account/accomplishments/verify/MH7UG7T56C52">Meta - React Basics</a>.</p>
</li>
<li><p><a target="_blank" href="https://www.coursera.org/account/accomplishments/records/N3E722CLNM9R">Meta - Advanced React</a>.</p>
</li>
<li><p><a target="_blank" href="https://roadmap.sh/react">Roadmap.sh - React</a>.</p>
</li>
</ul>
</li>
<li><p>Web accessibility.</p>
<ul>
<li><p><a target="_blank" href="https://www.udacity.com/enrollment/ud891">Web Accessibility</a>.</p>
</li>
<li><p><a target="_blank" href="https://www.coursera.org/account/accomplishments/records/GMFD764G5QBR">Meta - HTML and CSS in depth</a>.</p>
</li>
<li><p><a target="_blank" href="https://youtube.com/playlist?list=PLNYkxOF6rcICWx0C9LVWWVqvHlYJyqw7g&amp;si=TpMsV4EwDGa2lSBV">A11ycasts with Rob Dodson</a>.</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p>Other topics.</p>
<ul>
<li><p>Authentication - <a target="_blank" href="https://www.edx.org/learn/computer-programming/the-world-wide-web-consortium-w3c-introduction-to-web-authentication">Introduction to Web Authentication</a>.</p>
</li>
<li><p>JWT - <a target="_blank" href="https://youtu.be/x5gLL8-M9Fo?si=QpD5KEP6WLEtY9mr">What are JSON Web Tokens?</a></p>
</li>
<li><p>Character Encodings - <a target="_blank" href="https://www.joelonsoftware.com/2003/10/08/the-absolute-minimum-every-software-developer-absolutely-positively-must-know-about-unicode-and-character-sets-no-excuses/">Must Know About Unicode and Character Sets</a>.</p>
</li>
<li><p>Time and Time Zones - <a target="_blank" href="https://www.pluralsight.com/courses/date-time-fundamentals">Date and Time Fundamentals</a>.</p>
</li>
<li><p>Storybook - <a target="_blank" href="https://www.pluralsight.com/courses/date-time-fundamentals">A Be</a><a target="_blank" href="https://egghead.io/courses/a-beginner-s-guide-to-storybook-7-with-react-56f61ecf">ginner’s Guide to Storybook 7 with React</a>.</p>
</li>
<li><p>Networking Concepts - <a target="_blank" href="https://yourdevopsmentor.com/blog/networking-for-devops-a-complete-guide/">Networking for DevOps – a Complete Guide</a>.</p>
</li>
<li><p>Docker - <a target="_blank" href="https://youtu.be/RqTEHSBrYFw?si=nBeGOu-R5e0b3uwy">Complete Docker Course</a>.</p>
</li>
<li><p>Pen Testing - <a target="_blank" href="https://www.breachlock.com/resources/blog/the-basics-of-penetration-testing/">The Basics of Penetration Testing</a>.</p>
</li>
<li><p>Documentation - <a target="_blank" href="https://developers.google.com/tech-writing">Technical Writing</a>.</p>
</li>
</ul>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Using browser storage]]></title><description><![CDATA[There are 3 main storage options within the browser. Use the following information to decide which option to use for your use case.
Session Storage
Session storage is a browser storage only accessible through client-side JavaScript in which the data ...]]></description><link>https://blogs.namitoyokota.com/using-browser-storage</link><guid isPermaLink="true">https://blogs.namitoyokota.com/using-browser-storage</guid><category><![CDATA[Browsers]]></category><category><![CDATA[JavaScript]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[storage]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Wed, 23 Oct 2024 12:51:38 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489676334/520ae754-c5d4-4684-948e-b4a1720741e7.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>There are <a target="_blank" href="https://blog.webdevsimplified.com/2020-08/cookies-localstorage-sessionstorage/">3 main storage options</a> within the browser. Use the following information to decide which option to use for your use case.</p>
<h2 id="heading-session-storage">Session Storage</h2>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Window/sessionStorage">Session storage</a> is a browser storage only accessible through client-side JavaScript in which the data stored is automatically deleted when the user closes the browser tab or window.</p>
<h3 id="heading-differences">Differences</h3>
<ul>
<li><p>Expiration: On tab close</p>
</li>
<li><p>Storage capacity: 5MB</p>
</li>
<li><p>Accessibility: Current tab</p>
</li>
</ul>
<h3 id="heading-code-example">Code example</h3>
<pre><code class="lang-jsx">sessionStorage.setItem(<span class="hljs-string">"firstName"</span>, <span class="hljs-string">"John"</span>);
sessionStorage.setItem(<span class="hljs-string">"lastName"</span>, <span class="hljs-string">"Doe"</span>);
sessionStorage.getItem(<span class="hljs-string">"firstName"</span>); <span class="hljs-comment">// John</span>
<span class="hljs-built_in">localStorage</span>.removeItem(<span class="hljs-string">"firstName"</span>);
</code></pre>
<h2 id="heading-local-storage">Local Storage</h2>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage">Local storage</a> is a browser storage only accessible through client-side JavaScript in which the data persists in the browser’s memory upon page refresh or window/tab close.</p>
<h3 id="heading-differences-1">Differences</h3>
<ul>
<li><p>Expiration: Never</p>
</li>
<li><p>Storage capacity: 10MB</p>
</li>
<li><p>Accessibility: Any window or tab with same origin</p>
</li>
</ul>
<h3 id="heading-code-example-1">Code example</h3>
<pre><code class="lang-jsx">localStroage.setItem(<span class="hljs-string">"firstName"</span>, <span class="hljs-string">"John"</span>);
localStroage.setItem(<span class="hljs-string">"lastName"</span>, <span class="hljs-string">"Doe"</span>);
<span class="hljs-built_in">localStorage</span>.getItem(<span class="hljs-string">"firstName"</span>) <span class="hljs-comment">// John</span>
sessionStorage.removeItem(<span class="hljs-string">"firstName"</span>);
</code></pre>
<h2 id="heading-cookies">Cookies</h2>
<p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies">Cookies</a> are another form of browser storage <a target="_blank" href="https://owasp.org/www-community/HttpOnly">only accessible by the server</a> and not by the client-side JavaScript. The data stored in cookies are persistent upon page refresh or window/tab close, until the expired date passes.</p>
<h3 id="heading-differences-2">Differences</h3>
<ul>
<li><p>Expiration: Manually set</p>
</li>
<li><p>Storage capacity: 4KB</p>
</li>
<li><p>Accessibility: Any window or tab with same origin</p>
</li>
</ul>
<h3 id="heading-code-example-2">Code example</h3>
<pre><code class="lang-jsx"><span class="hljs-built_in">document</span>.cookie = <span class="hljs-string">"firstName=John; expires=${new Date(2025, 0, 1).toUTCString()}"</span>; <span class="hljs-comment">// 01-01-2025</span>
<span class="hljs-built_in">document</span>.cookie = <span class="hljs-string">"lastName=Doe; expires=${new Date(9999, 0, 1).toUTCString()}"</span>; <span class="hljs-comment">// Never expires</span>
<span class="hljs-built_in">document</span>.cookie <span class="hljs-comment">// firstName=John; lastName=Doe</span>
<span class="hljs-built_in">document</span>.cookie = <span class="hljs-string">"firstName=; expires=Thu, 01 Jan 1970 00:00:00 GMT"</span>
</code></pre>
]]></content:encoded></item><item><title><![CDATA[Removing unused frontend packages]]></title><description><![CDATA[Depcheck is a tool for analyzing the dependencies in a project to see: how each dependency is used, which dependencies are useless, and which dependencies are missing from package.json.
The package can be installed and ran using the following command...]]></description><link>https://blogs.namitoyokota.com/removed-unused-packages</link><guid isPermaLink="true">https://blogs.namitoyokota.com/removed-unused-packages</guid><category><![CDATA[npm]]></category><category><![CDATA[Yarn]]></category><category><![CDATA[Frontend Development]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Wed, 23 Oct 2024 12:27:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489691652/c25cce76-ae9c-4de9-b57a-a25cf33147e2.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://github.com/depcheck/depcheck">Depcheck</a> is a tool for analyzing the dependencies in a project to see: how each dependency is used, <a target="_blank" href="https://stackoverflow.com/questions/22675725/how-to-find-unused-packages-in-package-json">which dependencies are useless</a>, and which dependencies are missing from <code>package.json</code>.</p>
<p>The package can be installed and ran using the following commands:</p>
<pre><code class="lang-bash">npm install depcheck -g
yarn global add depcheck

depcheck
</code></pre>
<p>Or you can use npx (a package runner):</p>
<pre><code class="lang-bash">npx depcheck
</code></pre>
<p>One thing to note: be careful removing packages within the <code>devDependencies</code> list. Although the packages in this list is not installed with the <code>--production</code> flag, it is typically <a target="_blank" href="https://docs.npmjs.com/specifying-dependencies-and-devdependencies-in-a-package-json-file">used for packages that are only needed for local development and testing</a>.</p>
]]></content:encoded></item><item><title><![CDATA[Opening VSCode from Visual Studio]]></title><description><![CDATA[If you are a full-stack developer mainly working in Visual Studio, it may be tempting to edit frontend files within the same software. However, this can be counter productive - especially if the frontend codebase has linting.
Imagine having to go thr...]]></description><link>https://blogs.namitoyokota.com/open-vscode-from-visual-studio</link><guid isPermaLink="true">https://blogs.namitoyokota.com/open-vscode-from-visual-studio</guid><category><![CDATA[vscode extensions]]></category><category><![CDATA[vscode]]></category><category><![CDATA[VSCode Tips]]></category><category><![CDATA[visual studio]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Thu, 26 Sep 2024 12:44:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489706973/2eba55a6-0dab-4258-ab1a-3d9d26993709.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>If you are a full-stack developer mainly working in Visual Studio, it may be tempting to edit frontend files within the same software. However, this can be counter productive - especially if the frontend codebase has linting.</p>
<p>Imagine having to go through each lint error and manually resolve them because the pull request pipeline failed with the message: <code>ESLint found too many warnings</code>. When you could’ve simply installed a few extensions in VSCode to automatically format the code changes to follow the specific coding standards that has been set.</p>
<p>From my research, there is no good linting or prettier plugins for formatting on save within Visual Studio. So for now, my solution is to recommend developers to open frontend files from VSCode - and there is a setting that helps us achieve this.</p>
<p>Once you open your repository in Visual Studio, locate file types you would like to always open with VSCode from the Solution Explorer. For my project, I selected 3 different file types: TypeScript (<code>.ts</code>), HTML (<code>.html</code>), and SCSS (<code>.scss</code>). For each file, right click and open the <code>Open With...</code> menu. From here, <code>Add</code> the VSCode executable, which is typically stored within the following path: <code>C:\\Users\\{USER}\\AppData\\Local\\Programs\\Microsoft VS Code</code>. Then use <code>Set as Default</code> button to open these file types in VSCode going forward.</p>
]]></content:encoded></item><item><title><![CDATA[Recommending VSCode Extensions]]></title><description><![CDATA[To recommend VSCode extensions within a certain repository, create a new JSON file under root: .vscode/extensions.json.
This then takes in an object with property recommendations as a list of strings. Each string is the Extension ID which can be foun...]]></description><link>https://blogs.namitoyokota.com/recommend-vscode-extensions</link><guid isPermaLink="true">https://blogs.namitoyokota.com/recommend-vscode-extensions</guid><category><![CDATA[vscode extensions]]></category><category><![CDATA[vscode]]></category><category><![CDATA[VSCode Tips]]></category><category><![CDATA[extensions]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[frontend]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Wed, 25 Sep 2024 12:18:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489722041/416a64c6-a0f7-4bb3-9cd5-b40fffd2a01e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>To <a target="_blank" href="https://code.visualstudio.com/docs/editor/extension-marketplace#_workspace-recommended-extensions">recommend VSCode extensions</a> within a certain repository, create a new JSON file under root: <code>.vscode/extensions.json</code>.</p>
<p>This then takes in an object with property <code>recommendations</code> as a list of strings. Each string is the Extension ID which can be found by going to the “Extensions” tab, clicking on the settings icon, then “Copy Extension ID”.</p>
<pre><code class="lang-json">{
    <span class="hljs-attr">"recommendations"</span>: [
        <span class="hljs-string">"dbaeumer.vscode-eslint"</span>,
        <span class="hljs-string">"esbenp.prettier-vscode"</span>,
        <span class="hljs-string">"ecmel.vscode-html-css"</span>,
        <span class="hljs-string">"sibiraj-s.vscode-scss-formatter"</span>,
        <span class="hljs-string">"formulahendry.auto-rename-tag"</span>,
        <span class="hljs-string">"kamikillerto.vscode-colorize"</span>,
        <span class="hljs-string">"deque-systems.vscode-axe-linter"</span>,
        <span class="hljs-string">"streetsidesoftware.code-spell-checker"</span>,
        <span class="hljs-string">"aaron-bond.better-comments"</span>,
        <span class="hljs-string">"vincaslt.highlight-matching-tag"</span>,
        <span class="hljs-string">"oderwat.indent-rainbow"</span>,
        <span class="hljs-string">"christian-kohler.path-intellisense"</span>,
        <span class="hljs-string">"YoavBls.pretty-ts-errors"</span>
    ]
}
</code></pre>
<p>Now, if any developers open the repository without <em>all</em> of the recommended repositories, a prompt automatically opens with the following action steps:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1727266592347/c4deeab0-b088-40a4-81a9-b5cdbc411033.png" alt class="image--center mx-auto" /></p>
]]></content:encoded></item><item><title><![CDATA[Are you senior developer ready?]]></title><description><![CDATA[The developer community consists of numerous articles on steps to becoming a senior developer. However, many of them tend to focus on the big picture concepts. In this article, I aim to provide a comprehensive list of practical tips you can follow. I...]]></description><link>https://blogs.namitoyokota.com/are-you-senior-developer-ready</link><guid isPermaLink="true">https://blogs.namitoyokota.com/are-you-senior-developer-ready</guid><category><![CDATA[senior-software-engineer]]></category><category><![CDATA[Career]]></category><category><![CDATA[promotion]]></category><category><![CDATA[Junior developer ]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Tue, 14 May 2024 20:59:04 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489736172/0799095c-9648-4389-8f33-ff544f7c289c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The developer community consists of numerous articles on steps to becoming a senior developer. However, many of them tend to focus on the big picture concepts. In this article, I aim to provide a comprehensive list of practical tips you can follow. I personally followed this list to become a senior developer without meeting the years of experience requirement.</p>
<hr />
<p>First, a leap from a junior developer to a senior developer makes up a long list of technical skills to differentiate yourself.</p>
<ul>
<li><p>Spend time learning security vulnerabilities and how to prevent them.</p>
</li>
<li><p>Write readable, maintainable, and scalable code.</p>
</li>
<li><p>Become a fire fighter. When urgent bugs are reported, remediate them efficiently.</p>
</li>
<li><p><a target="_blank" href="https://blogs.namitoyokota.com/reviewers-guide-to-effective-code-review">Deeply review code and provide useful feedback</a>.</p>
</li>
<li><p>Become proficient in researching new technologies and developing POCs (proof of concept).</p>
</li>
<li><p>Come up with creative and clever solutions that can be used company wide.</p>
</li>
<li><p>Create or refine coding standards and style guides.</p>
</li>
<li><p>Understand different types of testing methods.</p>
</li>
<li><p>Place testing rules and group testing meetings to production bugs.</p>
</li>
<li><p>Learn how to run mob sessions and pair programming meetings effectively and efficiently.</p>
</li>
<li><p>Have a strong understanding of the software architecture and the release process used by your team.</p>
</li>
<li><p>Always know the pros and cons of the method/technology that your project is using. Never say, “That’s how it’s always been.”</p>
</li>
<li><p>Contribute to the company wiki pages and write new documentations as needed.</p>
</li>
<li><p>Be up to date on the latest technology news and trends. Subscribing to newsletters is a great way to achieve this.</p>
</li>
<li><p>Mentor junior developers to provide them with resources and opportunities to improve. Learn to delegate your coding tasks.</p>
</li>
<li><p>Communicate with stakeholders (keep in mind the technical limitations). Learn to estimate and avoid over-promising.</p>
</li>
</ul>
<p>On top of these technical skills, you should also improve your personal skills.</p>
<ul>
<li><p>Become reliable, reachable, and consistent. Stay true to your word. Respond to messages in a timely manner.</p>
</li>
<li><p>Be precise in your speech. Avoid misunderstanding between your teammates.</p>
</li>
<li><p>Learn how to lead a meeting. Make sure that all opinions are heard.</p>
</li>
<li><p>Learn how to share your opinion. Be open to receiving feedback.</p>
</li>
<li><p>Learn to work in a fast-pace environment without distractions.</p>
</li>
<li><p>Encourage others to do their best and provide support when they are struggling.</p>
</li>
<li><p>Be optimistic and positive in meetings and try to add a smile.</p>
</li>
</ul>
<p>Lastly, create a brag document to provide a comprehensive list of your contributions to show your manager when asking for a promotion. Best of luck!</p>
]]></content:encoded></item><item><title><![CDATA[Autosaving user inputs]]></title><description><![CDATA[A few weeks into joining a new project, we received a bug report in our production environment. The error was from Dynamo DB: Throughput exceeded exception
Your request rate is too high. The AWS SDKs for DynamoDB automatically retry requests that rec...]]></description><link>https://blogs.namitoyokota.com/autosaving-user-inputs</link><guid isPermaLink="true">https://blogs.namitoyokota.com/autosaving-user-inputs</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[autosave]]></category><category><![CDATA[APIs]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[frontend]]></category><category><![CDATA[Tutorial]]></category><category><![CDATA[ideas]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Mon, 13 May 2024 22:34:33 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489751201/03fd405b-7275-47f4-9e78-72baf9e9e9ba.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>A few weeks into joining a new project, we received a bug report in our production environment. The error was from <a target="_blank" href="https://aws.amazon.com/dynamodb/">Dynamo DB</a>: <a target="_blank" href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html">Throughput exceeded exception</a></p>
<pre><code class="lang-plaintext">Your request rate is too high. The AWS SDKs for DynamoDB automatically retry requests that receive this exception. Your request is eventually successful, unless your retry queue is too large to finish. Reduce the frequency of requests using Error retries and exponential backoff.
</code></pre>
<p>The cause for this issue was our autosave feature. On every user input (text input, radio buttons, checkboxes) change, we were triggering an API request to save the changes. Since our users were familiar with the user interface and clicked through the site quickly, we never caught this error during development and QA testing.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715639375659/a16c93e8-2883-42b7-9dcb-738b7b4a20c2.png" alt class="image--center mx-auto" /></p>
<p>My solution, as always, was to look for how other products approach it. Looking at Hashnode, they have an autosave feature where the user changes text of the draft blog, and there’s a few second wait before the save is triggered. This way, save request isn’t on each keydown event, and instead is using a debounce mechanism to save when user stops typing.</p>
<p>To achieve this, I decided to create a new <a target="_blank" href="https://angular.io/guide/dependency-injection-overview">dependency injectable</a> class: <a target="_blank" href="https://en.wikipedia.org/wiki/Autosave">autosave</a> service.</p>
<div data-node-type="callout">
<div data-node-type="callout-emoji">🚩</div>
<div data-node-type="callout-text">I will be using the Angular framework for this project.</div>
</div>

<h2 id="heading-definition-of-done">Definition of done</h2>
<ul>
<li><p>An abstract service to allow different data type implementations.</p>
</li>
<li><p>Autosave service should be dependency injectable by any component.</p>
</li>
<li><p>Component can request a piece of data to save to the database on next timer tick.</p>
</li>
<li><p>Component should have the ability to save immediately (ignoring the debounce mechanism).</p>
</li>
<li><p>When the save request errors out, data should not be saved again until a new change is made.</p>
</li>
<li><p>Status of the save should be visible to the component for user feedback.</p>
</li>
<li><p>Frequency of the tick should be configurable.</p>
</li>
</ul>
<h2 id="heading-implementation">Implementation</h2>
<p>Let’s start by creating a status enum indicating when a request has been received, saving request but have not received response from API, save complete. This will be a public property that can be accessed by the component to display in the user interface.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-built_in">enum</span> SaveStatus {
    UNSAVED = <span class="hljs-string">'Unsaved changes'</span>,
    SAVING = <span class="hljs-string">'Saving'</span>,
    SAVED = <span class="hljs-string">'Changes saved'</span>,
    NULL = <span class="hljs-string">'No changes'</span>
}
</code></pre>
<p>As mentioned in the requirements, I wanted the class to be an <a target="_blank" href="https://www.tutorialsteacher.com/typescript/abstract-class">abstract class</a> meaning multiple services can be implemented with different kinds of data.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">abstract</span> <span class="hljs-keyword">class</span> AutosaveService&lt;T&gt; {
    <span class="hljs-comment">/** Request object to save on the next trigger */</span>
    <span class="hljs-keyword">protected</span> dataToSave: T = <span class="hljs-literal">null</span>;
}
</code></pre>
<p>Using <a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/generics.html">generics</a>, the base class will take in a type that indicates the instances of the data that will be sent to the API.</p>
<p>To allow the child components to listen to the status change and display in the UI, we can use the <code>[BehaviorSubject](&lt;https://rxjs.dev/api/index/class/BehaviorSubject&gt;)</code> from RxJS.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/** Current status of the save */</span>
<span class="hljs-keyword">protected</span> status = <span class="hljs-keyword">new</span> BehaviorSubject&lt;SaveStatus&gt;(SaveStatus.NULL);

<span class="hljs-comment">/** Current status of the save */</span>
status$ = <span class="hljs-built_in">this</span>.status.asObservable();
</code></pre>
<p>In the same way, tracking errors will be important to prevent multiple requests of the same value.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/** Indicates error happened on last API call */</span>
<span class="hljs-keyword">protected</span> error = <span class="hljs-keyword">new</span> BehaviorSubject&lt;<span class="hljs-built_in">boolean</span>&gt;(<span class="hljs-literal">false</span>);

<span class="hljs-comment">/** Indicates error happened on last API call */</span>
error$ = <span class="hljs-built_in">this</span>.error.asObservable();
</code></pre>
<p>Now, on to the fun part. We’ll need a way to start a timer when a request is first sent. When the timer goes off, an API request should be sent to save the data. The <a target="_blank" href="https://rxjs.dev/api/index/function/timer">timer observable</a> from RxJS is a perfect usecase for this.</p>
<p>It is important to note here that we account for when another request has been sent prior to the first timer completing. In this case, we will restart the timer and update the data object.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/** Observable for timer ticks */</span>
<span class="hljs-keyword">private</span> timer$: Observable&lt;<span class="hljs-built_in">number</span>&gt;;

<span class="hljs-comment">/** Subscription listening to latest timer */</span>
<span class="hljs-keyword">private</span> timerSubscription: Subscription;

<span class="hljs-comment">/** Frequency of the timer tick in milliseconds */</span>
<span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> tickFrequency = <span class="hljs-number">5000</span>;

<span class="hljs-keyword">constructor</span>(<span class="hljs-params"></span>) {}

<span class="hljs-comment">/** Calls API to save data */</span>
<span class="hljs-keyword">abstract</span> saveData(): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt;;

<span class="hljs-comment">/**
 * Requests service to save data on the next tick
 * @param request Data to save
 */</span>
requestSave(request: T): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.timerSubscription?.unsubscribe();

    <span class="hljs-built_in">this</span>.timer$ = timer(<span class="hljs-built_in">this</span>.tickFrequency);
    <span class="hljs-built_in">this</span>.dataToSave = request;
    <span class="hljs-built_in">this</span>.error.next(<span class="hljs-literal">false</span>);
    <span class="hljs-built_in">this</span>.status.next(SaveStatus.UNSAVED);

    <span class="hljs-built_in">this</span>.listenToTimer();
}

<span class="hljs-comment">/**
 * Triggers save on timer tick
 */</span>
<span class="hljs-keyword">private</span> listenToTimer(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.timerSubscription = <span class="hljs-built_in">this</span>.timer$.pipe(first()).subscribe(<span class="hljs-function">() =&gt;</span> {
        <span class="hljs-keyword">const</span> triggerSave = <span class="hljs-built_in">this</span>.dataToSave &amp;&amp; !<span class="hljs-built_in">this</span>.error.getValue() &amp;&amp; <span class="hljs-built_in">this</span>.status.getValue() === SaveStatus.UNSAVED;
        <span class="hljs-keyword">if</span> (triggerSave) {
            <span class="hljs-built_in">this</span>.saveData();
        }
    });
}
</code></pre>
<p>Let’s add the ability to save immediately ignoring the timer. This will be useful when the user wants to manually save recent changes or when the user navigates away from the page before the changes are saved.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/**
 * Saves data at the moment of the request
 * @param request Data to save
 */</span>
saveNow(request: T): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; {
    <span class="hljs-built_in">this</span>.status.next(SaveStatus.UNSAVED);
    <span class="hljs-built_in">this</span>.dataToSave = request;
    <span class="hljs-built_in">this</span>.error.next(<span class="hljs-literal">false</span>);

    <span class="hljs-keyword">return</span> <span class="hljs-built_in">this</span>.saveData();
}
</code></pre>
<p>We also need an ability to clear the request after saving changes. This will be an easy way to clear the previous request after a successful save.</p>
<pre><code class="lang-typescript"><span class="hljs-comment">/**
 * Empties save request
 */</span>
clearRequest(): <span class="hljs-built_in">void</span> {
    <span class="hljs-built_in">this</span>.status.next(SaveStatus.SAVED);
    <span class="hljs-built_in">this</span>.dataToSave = <span class="hljs-literal">null</span>;
    <span class="hljs-built_in">this</span>.error.next(<span class="hljs-literal">false</span>);
}
</code></pre>
<p>Boom! The abstract class is now complete!</p>
<p>To start using the autosave feature, create a brand new class with data type you wish to save. Then the <code>saveData()</code> method should be implemented to perform the API request.</p>
<pre><code class="lang-typescript"><span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AutosavePersonService <span class="hljs-keyword">extends</span> AutosaveService&lt;Person&gt; {
    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> apiService: ApiService</span>) {
        <span class="hljs-built_in">super</span>();
    }

    <span class="hljs-comment">/**
     * Calls API to save person's data
     */</span>
    saveData(): <span class="hljs-built_in">Promise</span>&lt;<span class="hljs-built_in">void</span>&gt; {
        <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
            <span class="hljs-built_in">this</span>.status.next(SaveStatus.SAVING);
            <span class="hljs-built_in">this</span>.apiService
                .save(<span class="hljs-built_in">this</span>.dataToSave)
                .then(<span class="hljs-function">() =&gt;</span> {
                    <span class="hljs-built_in">this</span>.clearRequest();
                    resolve();
                })
                .catch(<span class="hljs-function">() =&gt;</span> {
                    <span class="hljs-built_in">this</span>.status.next(SaveStatus.UNSAVED);
                    <span class="hljs-built_in">this</span>.error.next(<span class="hljs-literal">true</span>);
                    reject();
                });
        });
    }
}
</code></pre>
<p>We are now ready to inject this class into any component you desire and autosave user input changes. Here is what that might look like:</p>
<pre><code class="lang-typescript"><span class="hljs-meta">@Component</span>({
    selector: <span class="hljs-string">'app-root'</span>,
    templateUrl: <span class="hljs-string">'./app.component.html'</span>,
    styleUrls: [<span class="hljs-string">'./app.component.scss'</span>],
})
<span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> AppComponent {
    <span class="hljs-comment">/** Data on the person */</span>
    person: Person;

    <span class="hljs-comment">/** Status of the autosave request */</span>  
    status = <span class="hljs-built_in">this</span>.autosavePersonService.status$;

    <span class="hljs-keyword">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> autosavePersonService: AutosavePersonService</span>) {}

    <span class="hljs-comment">/**
     * Fires save request to autosave service
     */</span>
    savePerson() : <span class="hljs-built_in">void</span> {
        <span class="hljs-built_in">this</span>.autosavePersonService.requestSave(<span class="hljs-built_in">this</span>.person);
    }

    <span class="hljs-comment">/**
     * Immediately saves changes on person object
     */</span>
    savePersonNow(): <span class="hljs-built_in">void</span> {
        <span class="hljs-built_in">this</span>.autosavePersonService.saveNow(<span class="hljs-built_in">this</span>.person);
    }
}
</code></pre>
<h2 id="heading-demo">Demo</h2>
<p>I’ve created a CodeSandbox project with the entire code from this writing.</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://codesandbox.io/s/autosave-service-34jpdy">https://codesandbox.io/s/autosave-service-34jpdy</a></div>
<p> </p>
<h2 id="heading-resources">Resources</h2>
<ul>
<li><p>TypeScript <a target="_blank" href="https://www.typescriptlang.org/docs/handbook/2/generics.html">Generics</a></p>
</li>
<li><p>RxJS <a target="_blank" href="https://rxjs.dev/api/index/class/BehaviorSubject">Behavior Subject</a> and <a target="_blank" href="https://www.learnrxjs.io/learn-rxjs/subjects/behaviorsubject">tutorial</a></p>
</li>
<li><p>RxJS <a target="_blank" href="https://rxjs.dev/guide/observable">Observable</a></p>
</li>
<li><p>RxJS <a target="_blank" href="https://rxjs.dev/api/index/function/timer">timer</a> and <a target="_blank" href="https://www.learnrxjs.io/learn-rxjs/operators/creation/timer">tutorial</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Catch TypeScript errors with Webpack]]></title><description><![CDATA[When I first joined my company, I was responsible for overseeing a new frontend project started by full-stack developers. This is a story about the first issue I resolved.
Problem
As full-stack developers tend to be backend developers with minimal fr...]]></description><link>https://blogs.namitoyokota.com/catch-typescript-errors-with-webpack</link><guid isPermaLink="true">https://blogs.namitoyokota.com/catch-typescript-errors-with-webpack</guid><category><![CDATA[TypeScript]]></category><category><![CDATA[webpack]]></category><category><![CDATA[error handling]]></category><category><![CDATA[error]]></category><category><![CDATA[Stack Overflow]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Sun, 12 May 2024 22:50:53 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489768484/aad57cb0-eff7-43ef-96ba-ef189b9afddb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>When I first joined my company, I was responsible for overseeing a new frontend project started by full-stack developers. This is a story about the first issue I resolved.</p>
<h2 id="heading-problem">Problem</h2>
<p>As full-stack developers tend to be backend developers with minimal frontend experience, our frontend project was barely functional.</p>
<p>One of the issues I found was that when running an instance locally, our builds were not failing on any TypeScript errors seen in the code editor.</p>
<p>For example, imagine a simply method that adds 2 numbers. As addition is a mathematical operation, both of the arguments are expecting a number type.</p>
<pre><code class="lang-typescript">add(num1: <span class="hljs-built_in">number</span>, num2: <span class="hljs-built_in">number</span>): <span class="hljs-built_in">number</span> {
    <span class="hljs-keyword">return</span> num1 + num2;
}

add(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>);     <span class="hljs-comment">// This is valid.</span>
add(<span class="hljs-string">'a'</span>, <span class="hljs-string">'b'</span>); <span class="hljs-comment">// This is not valid.</span>
</code></pre>
<p>With the above implementation, <code>add('a', 'b');</code> should fail at compile time as string were passed in as parameters. However, in our codebase, the build completes without any errors or warnings, and the bug will only found at runtime.</p>
<p>This is a major problem as <a target="_blank" href="https://www.typescriptlang.org/why-create-typescript/">type checking is the whole point of using TypeScript</a>. God only knows how many errors we have been ignoring. Our codebase is essentially all using JavaScript at this point.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715554116856/2bfaa162-e3c5-41de-93de-aa74ac00d38b.png" alt class="image--center mx-auto" /></p>
<h2 id="heading-solution">Solution</h2>
<p>With the almighty Google search, I found a commonly used npm package known as <code>[fork-ts-checker-webpack-plugin](&lt;https://www.npmjs.com/package/fork-ts-checker-webpack-plugin&gt;)</code>. ****This is a webpack plugin which adds TypeScript’s type checking process then outputs the results in the command line.</p>
<p>To implement this plugin, first install the package: <code>npm i fork-ts-checker-webpack-plugin</code>.</p>
<p>Then, navigate to the project’s <code>webpack.config.js</code> file. Within the file, you will need to add an import line at the top, as well as an instance of the class to the <code>plugins</code> array:</p>
<pre><code class="lang-jsx"><span class="hljs-keyword">const</span> ForkTsCheckerWebpackPlugin = <span class="hljs-built_in">require</span>(<span class="hljs-string">'fork-ts-checker-webpack-plugin'</span>);

<span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">plugins</span>: [<span class="hljs-keyword">new</span> ForkTsCheckerWebpackPlugin()],
  ...
};
</code></pre>
<p>Keep in mind that the <code>ts-loader</code> package is required for this plugin to work. Loader should look like the following:</p>
<pre><code class="lang-jsx"><span class="hljs-built_in">module</span>.exports = {
  <span class="hljs-attr">context</span>: __dirname,
  <span class="hljs-attr">entry</span>: <span class="hljs-string">'./src/index.ts'</span>,
  <span class="hljs-attr">resolve</span>: {
    <span class="hljs-attr">extensions</span>: [<span class="hljs-string">".ts"</span>, <span class="hljs-string">".tsx"</span>, <span class="hljs-string">".js"</span>],
  },
  <span class="hljs-attr">module</span>: {
    <span class="hljs-attr">rules</span>: [
      {
        <span class="hljs-attr">test</span>: <span class="hljs-regexp">/\\.tsx?$/</span>,
        loader: <span class="hljs-string">'ts-loader'</span>,
      }
    ]
  },
};
</code></pre>
<p>Voila! Now the terminal will display each and every TypeScript error! As a result, I was able to catch over 120 type errors in our codebase which I spent rest of the day resolving 😄</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1715554084754/6a813fd9-6e7a-4577-ab20-aae1d831e40f.png" alt class="image--center mx-auto" /></p>
<hr />
<p>Thanks to <a target="_blank" href="https://stackoverflow.com/questions/64592611/webpack-is-not-failing-on-typescript-error">this Stack Overflow thread</a> for discussing this issue.</p>
]]></content:encoded></item><item><title><![CDATA[How I accidentally contributed to an open-source project]]></title><description><![CDATA[I can’t do my job
My local environment stopped working. The command to run and build an Aurelia project, a frontend web framework built by the original creator of Angular, mysteriously failed with the following error message:
error: Error: spawn EINV...]]></description><link>https://blogs.namitoyokota.com/how-i-accidentally-contributed-to-an-open-source-project</link><guid isPermaLink="true">https://blogs.namitoyokota.com/how-i-accidentally-contributed-to-an-open-source-project</guid><category><![CDATA[spawn]]></category><category><![CDATA[Aurelia]]></category><category><![CDATA[Node.js]]></category><category><![CDATA[Windows]]></category><category><![CDATA[cli]]></category><category><![CDATA[Security]]></category><category><![CDATA[child_process]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Wed, 17 Apr 2024 18:39:57 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489781762/fb41e39b-ea0c-43e0-a837-6eb7677cf0c6.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h3 id="heading-i-cant-do-my-job">I can’t do my job</h3>
<p>My local environment stopped working. The <a target="_blank" href="https://aurelia.io/docs/cli/basics#running-your-aurelia-app">command</a> to run and build an Aurelia project, a frontend web framework built by the original creator of Angular, mysteriously failed with the following error message:</p>
<pre><code class="lang-plaintext">error: Error: spawn EINVAL
  at ChildProcess.spawn (node:internal/child_process:421:11)
  at spawn (node:child_process:761:9)
  ...
</code></pre>
<h3 id="heading-the-almighty-google-search">The almighty Google search</h3>
<p>Since none of the typical solutions like reinstalling dependencies or reverting back the recent changes worked, I searched on the internet for a solution.</p>
<p>Eventually, I came across a <a target="_blank" href="https://discourse.nodered.org/t/not-starting-on-window-11-error-spawn-einval/87153">discussion forum</a> from an open-source project called <a target="_blank" href="https://nodered.org/">Node-RED</a>. Node-RED is a low-code development tool for visual programming. The project maintainers had come across the same <a target="_blank" href="https://github.com/node-red/node-red/issues/4653">error message</a> and they found that the recent <a target="_blank" href="https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2/">security release</a> from <a target="_blank" href="https://nodejs.org/en">Node.js</a> was the root cause.</p>
<p>Node.js codebase included a method in which “a malicious command line argument can inject arbitrary commands and achieve code execution even if the shell option is not enabled.” This impacted all <code>Windows</code> users in active release lines of <code>18.x</code>, <code>20.x</code>, and <code>21.x</code>.</p>
<p>Since I am on <code>Windows 11</code> using their latest <code>21.7.3</code>, this was likely the issue. Node-RED maintainers were able to <a target="_blank" href="https://github.com/node-red/node-red/pull/4652">resolve this issue</a> quickly by adding an option property of <code>shell: true</code> to the <code>spawn()</code> constructor argument.</p>
<h3 id="heading-the-cli-repository">The CLI repository</h3>
<p>Looking at the <a target="_blank" href="https://github.com/aurelia/cli">Aurelia's CLI project on GitHub</a>, I found a line referencing the exact <code>spawn</code> method without the <code>shell</code> option set.</p>
<p>However, the Aurelia develompent team has since moved to <a target="_blank" href="https://docs.aurelia.io/developer-guides/migrating-to-aurelia-2">completely rewrite</a> the project (<a target="_blank" href="https://docs.aurelia.io/">Aurelia v2</a>) so the repository has not been updated in 6 months.</p>
<p><img src="https://www.monkeyuser.com/2024/sacrifice/273-sacrifice.jpg" alt="Sacrifice" /></p>
<h2 id="heading-solutions-in-order-from-worst-to-best">Solutions (in order from worst to best)</h2>
<h3 id="heading-stop-using-windows">Stop using Windows</h3>
<p>This is not an option since I work for an organization with 99% of developers using Windows. However, good news is that our servers are all Linux; therefore, this error is only thrown during local development.</p>
<h3 id="heading-downgrade-nodejs">Downgrade Node.js</h3>
<p>Downgrading the Node.js version to the latest LTS release will <em>solve</em> the problem for now. However, this is a temporary solution as more developers will run into this issue upon a Node.js update.</p>
<p>Additionally, since no one has yet reported this issue on their GitHub issues page, I opened a <a target="_blank" href="https://github.com/aurelia/cli/issues/1205">new thread</a> explaining the issue I was having as well as the solution.</p>
<h3 id="heading-contribute-to-the-open-source-project">Contribute to the open-source project</h3>
<p>Within a few hours of writing a thorough explanation of my findings, the maintainer of the project commented on the issue asking for me to create a pull request.</p>
<p>Up to this point, I’ve never contributed or even attempted to contribute to an open-source project. This was also an CLI project which I don’t have experience working on. Not only that, the project has over 400 stars and 5,000 weekly downloads on npm.</p>
<p>Despite the hesitation, my manager encouraged me to attempt making the change. He thought that it would be a great experience for me.</p>
<p>With a few minor roadblocks, I manged to push the <a target="_blank" href="https://github.com/aurelia/cli/pull/1206">code change</a> and the package was released to npm a few days later. Installing the new version on my machine, our project started working again.</p>
<p>Throughout this journey, I learned how to think about open-source contribution. Within the developer community, it is commonly understood that contributing to open-source is how you can get a good job. However, I think we might have it backwards.</p>
<blockquote>
<p>Contributing to open source doesn’t make you a good developer. Good developers contribute to open-source.</p>
</blockquote>
<h2 id="heading-managing-nodejs-versions-properly">Managing Node.js versions properly</h2>
<p>To this day, I'm not sure how my machine automatically updated the Node.js version but my speculation is <a target="_blank" href="https://chocolatey.org/">Chocolatey</a>, an optionally installed package manager upon installation of Node.js. However, my big take away is that I now have an approach to managing the versions intentionally:</p>
<ul>
<li><p>Decide on an LTS release to use everywhere (local and servers).</p>
</li>
<li><p>Match your machine’s version with the production server.</p>
</li>
<li><p>Subscribe to the <a target="_blank" href="https://nodejs.org/en/blog">Node.js blog</a> and manually install any new releases to test your local environment. After confirming, downgrade to the LTS version. If the latest version fails one of your tools, search the repository online (typically on GitHub) and report the issue if there isn't one already.</p>
</li>
<li><p>Manage these versions using <a target="_blank" href="https://github.com/nvm-sh/nvm">nvm</a>.</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Beginner's Guide to CSS Grid]]></title><description><![CDATA[What is Grid?
Grid is a new CSS layout module created to support a two-dimensional layout system.

How to use it
Define Container
To start using CSS Grid, create a div element within the HTML, then define that element to be a grid container within th...]]></description><link>https://blogs.namitoyokota.com/beginners-guide-to-css-grid</link><guid isPermaLink="true">https://blogs.namitoyokota.com/beginners-guide-to-css-grid</guid><category><![CDATA[CSS]]></category><category><![CDATA[CSS Grid]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[frontend]]></category><category><![CDATA[Front-end Development]]></category><category><![CDATA[layout]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Mon, 27 Nov 2023 06:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489799016/a7790008-7c15-483b-89c6-53373ce20917.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-grid">What is Grid?</h2>
<p><strong>Grid</strong> is a new CSS layout module created to support a two-dimensional layout system.</p>
<hr />
<h2 id="heading-how-to-use-it">How to use it</h2>
<h3 id="heading-define-container">Define Container</h3>
<p>To start using CSS Grid, <strong>create</strong> a div element within the HTML, then <strong>define</strong> that element to be a <strong>grid</strong> container within the CSS. This sets the elements inside of the container to be the child elements directly affected by the grid settings. Keep in mind that default configurations have already been set at this point.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Box 1<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Box 2<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Box 3<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">display</span>: grid;
}
</code></pre>
<h3 id="heading-define-templates">Define Templates</h3>
<p>Next, define columns and/or row <strong>templates</strong>. Columns lay the elements <em>horizontally</em>, and rows lay the elements <em>vertically</em>. These values are <em>space-separated</em> and represent the track (width, length) size of the child elements.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">grid-template-columns</span>: none; <span class="hljs-comment">/** Default */</span>
    <span class="hljs-attribute">grid-template-rows</span>: none; <span class="hljs-comment">/** Default */</span>

    <span class="hljs-attribute">grid-template-columns</span>: auto <span class="hljs-number">150px</span>;
    <span class="hljs-attribute">grid-template-rows</span>: auto min-content;
    <span class="hljs-attribute">grid-template-rows</span>: auto <span class="hljs-number">150px</span>;
    <span class="hljs-attribute">grid-template-rows</span>: <span class="hljs-number">1</span>fr <span class="hljs-number">1</span>fr;
    <span class="hljs-attribute">grid-template-rows</span>: <span class="hljs-built_in">repeat</span>(<span class="hljs-number">2</span>, <span class="hljs-number">1</span>fr);
}
</code></pre>
<p>Here are examples of defining a template for <strong>columns</strong>.</p>
<p>These are some of the most commonly used size <strong>properties</strong>:</p>
<ul>
<li><p><code>fr</code> unit represents a fraction of the available space in the grid container</p>
</li>
<li><p><code>auto</code> sets the size based on the content that is inside them</p>
</li>
<li><p><code>{number}px</code> defines a static size of the element</p>
</li>
<li><p><code>repeat()</code> notation can be used to repeat all of a section of the track listing</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739812623140/02ba22cd-1db7-4670-8457-39f0a7fdc70f.png" alt class="image--center mx-auto" /></p>
<p>Here are example use cases for <strong>row</strong> templates.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739812646041/405fce3a-66c9-43e6-a5a6-a377820cf48a.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-gaps">Gaps</h3>
<p>Now that you have the basic layouts, consider configuring <strong>gaps</strong> next. Gaps can be set at the row or column level, and they define the spaces between the child elements. The default value for both is 0.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">column-gap</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">row-gap</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<p>Consider the following examples. The first example has 3 elements laid out horizontally (<code>grid-template-columns</code>). Notice that there are 10 pixels of space between the 1st and the 2nd element, as well as the 2nd and the 3rd element. These gaps are added between all of the child elements. In the second example, the elements are laid out vertically (<code>grid-template-rows</code>) and the gaps are set to 10 pixels by rows, as the vertical spaces between the 2 elements indicate.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739812667519/812fc169-96fb-46d3-b477-30d84cca16a1.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-justifications">Justifications</h3>
<p>A couple more to go. Configuring <strong>justifications</strong>. This setting allows you to set the <em>horizontal</em> location of the child elements. Let's look at a common use case.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">justify-content</span>: center;
}
</code></pre>
<p>As you can see below, the child element with 50 pixels width is set in the center of the container not taking any extra space.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739812687537/0cf9796c-a008-4a97-a7bb-24e033f2a85f.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-alignment">Alignment</h3>
<p>Almost done. Lastly, you can also configure alignments. This is very similar to justifications with a few differences. Alignments allow the <em>vertical</em> location of the child elements to be set. Let's try a common use case once again: <code>center</code>.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">align-items</span>: center;
}
</code></pre>
<p>In the final example below, you can see that the height of the element is set at 50 pixels and the container is set to 200 pixels. Because of the align-items property, the child is centered in the container.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739812718587/8f7137ae-de0b-4e37-8f9c-64d8f3b35e62.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-explore">Explore</h3>
<p>Now that you've learned the basics, try them out in your projects! As you test them locally, you can use Chrome DevTools to inspect and CSS Grid! Here is a <a target="_blank" href="https://developer.chrome.com/docs/devtools/css/grid/">guide</a> to doing just that! Consider checking out some of the links below as well. Thanks for reading!</p>
<hr />
<h3 id="heading-learn-more-about-grid">Learn more about Grid</h3>
<ul>
<li><p><a target="_blank" href="https://css-tricks.com/snippets/css/complete-guide-grid/">CSS Tricks - A Complete Guide to CSS Grid</a></p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/grid">Mozilla - CSS Grid</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Beginner's Guide to CSS Flexbox]]></title><description><![CDATA[What is Flexbox?
Flexbox is a CSS layout module that provides an efficient way to dynamically layout, align and distribute space among items in a container.

How to use it
Define Container
To start using flexbox, create a div element within the HTML,...]]></description><link>https://blogs.namitoyokota.com/beginners-guide-to-css-flexbox</link><guid isPermaLink="true">https://blogs.namitoyokota.com/beginners-guide-to-css-flexbox</guid><category><![CDATA[CSS]]></category><category><![CDATA[flexbox]]></category><category><![CDATA[Frontend Development]]></category><category><![CDATA[frontend]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Sun, 26 Nov 2023 06:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489814458/a3d3ead0-18a5-4564-bd41-6433c0714b4b.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-what-is-flexbox">What is Flexbox?</h2>
<p><strong>Flexbox</strong> is a CSS layout module that provides an efficient way to dynamically layout, align and distribute space among items in a container.</p>
<hr />
<h2 id="heading-how-to-use-it">How to use it</h2>
<h3 id="heading-define-container">Define Container</h3>
<p>To start using flexbox, <strong>create</strong> a div element within the HTML, then <strong>define</strong> that element to be a flex container within the CSS. This sets the elements inside of the container to be child elements affected by the flexbox settings. Keep in mind that default configurations have already been set at this point.</p>
<pre><code class="lang-xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"container"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Box 1<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Box 2<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span>&gt;</span>Box 3<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
</code></pre>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">display</span>: flex;
}
</code></pre>
<h3 id="heading-direction">Direction</h3>
<p>Next, configure the <strong>direction</strong> that you want the child elements to be layout: <code>row</code> or <code>column</code>.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">flex-direction</span>: row; <span class="hljs-comment">/** Default */</span>
    <span class="hljs-attribute">flex-direction</span>: column;
}
</code></pre>
<p>Here is an example of the 2 directions. Row (set by default) lays out the element horizontally, whereas column sets the element vertically.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739812311412/9d38e788-bf6a-4bcf-9c13-dce512363932.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-wrapping">Wrapping</h3>
<p>Next up, configuring <strong>wrapping</strong>. By default, the child elements will all try to fit into one line. Changing this setting allows you to control what happens to the child elements in case of overflow.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">flex-wrap</span>: nowrap; <span class="hljs-comment">/** Default */</span>
    <span class="hljs-attribute">flex-wrap</span>: wrap;
}
</code></pre>
<p>Take a look at the examples below. No wrap (set by default) is squeezing all of the elements to be on the same line, whereas the wrap setting pushes them onto the next line.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739812333908/1e6731d6-5d8d-40d3-8ee0-beea5843329a.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-gaps">Gaps</h3>
<p>Now that you have understood the basic layouts, consider configuring <strong>gaps</strong>. Gaps can be set at the row or column level, and they define the spaces between the child elements. The default value for both is 0.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">column-gap</span>: <span class="hljs-number">10px</span>;
    <span class="hljs-attribute">row-gap</span>: <span class="hljs-number">10px</span>;
}
</code></pre>
<p>Consider the following examples. The first example has 3 elements laid out horizontally (<code>flex-direction: row</code>) and there are 10 pixels of spaces between the 1st and 2nd element, and 2nd and 3rd element. In the second example, the elements are laid out vertically (<code>flex-direction: column</code>) and the gaps are set to 10 pixels by rows, as the vertical spaces between each element indicate.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739812355947/dff74200-7206-4fc2-b82e-8bfb6e3b3ee4.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-justifications">Justifications</h3>
<p>A couple more to go. Configuring <strong>justifications</strong>. This setting allows you to set the <em>horizontal</em> location of the child elements. Let's look at 2 common use cases: <code>center</code> and <code>space-between</code>.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">justify-content</span>: center;
    <span class="hljs-attribute">justify-content</span>: space-between;
}
</code></pre>
<p>In the top example from the image below, you will see 1 element inside of a flexbox centered horizontally. This can also be achieved when more than one element exists within the container. In the bottom example, there are 2 elements spaced apart, hence the keyword <code>space-between</code>: one on the left, and the second on the right.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739812373758/0dbaa2a4-ca30-4735-a425-a091d70fa73d.png" alt class="image--center mx-auto" /></p>
<h3 id="heading-alignment">Alignment</h3>
<p>Almost done. Lastly, you can also configure <strong>alignments</strong>. This is very similar to justifications with a few differences. Alignments allow the <em>vertical</em> location of the child elements to be set. Let's try using 2 commonly used keywords: <code>center</code> and <code>stretch</code>.</p>
<pre><code class="lang-css"><span class="hljs-selector-class">.container</span> {
    <span class="hljs-attribute">align-items</span>: center;
    <span class="hljs-attribute">align-items</span>: stretch;
}
</code></pre>
<p>The first example is using the center keyword. As you can see, while the height of the container is set at 200 pixels, the element is laid out in the center of the vertical axis. In the second example, there are 2 elements in one row, but the height of both elements is "stretched" to fix the 200-pixel height of the container.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1739812390692/71e41f75-a31f-4db1-8078-93d63d7bc763.png" alt class="image--center mx-auto" /></p>
<hr />
<h3 id="heading-explore">Explore</h3>
<p>Now that you've learned the basics, try them out in your projects! As you test them locally, you can use Chrome DevTools to inspect and CSS Flexbox. Here is a <a target="_blank" href="https://developer.chrome.com/docs/devtools/css/flexbox/">guide</a> to doing just that! Consider checking out some of the links below as well.</p>
<hr />
<h3 id="heading-learn-more-about-flexbox">Learn more about Flexbox</h3>
<ul>
<li><p><a target="_blank" href="https://css-tricks.com/snippets/css/a-guide-to-flexbox/">CSS Tricks - A Complete Guide to Flexbox</a></p>
</li>
<li><p><a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/CSS/flex">Mozilla - CSS Flex</a></p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Reviewer’s Guide to Effective Code Review]]></title><description><![CDATA[Code review is a one of the least focused responsibilities in our daily tasks as developers. Providing effective feedback to pull requests can significantly increase the quality of the codebase decreasing bugs, tech debts, and future refactors. Here ...]]></description><link>https://blogs.namitoyokota.com/reviewers-guide-to-effective-code-review</link><guid isPermaLink="true">https://blogs.namitoyokota.com/reviewers-guide-to-effective-code-review</guid><category><![CDATA[Pull Requests]]></category><category><![CDATA[maintainability]]></category><category><![CDATA[clean code]]></category><category><![CDATA[readability]]></category><category><![CDATA[scalability]]></category><category><![CDATA[Git]]></category><category><![CDATA[Feedback]]></category><dc:creator><![CDATA[Namito Yokota]]></dc:creator><pubDate>Tue, 21 Nov 2023 06:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1741489832658/9d618c73-ad5b-485b-ae7a-bec67c07e911.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Code review is a one of the least focused responsibilities in our daily tasks as developers. Providing effective feedback to pull requests can significantly increase the quality of the codebase decreasing bugs, tech debts, and future refactors. Here is a detailed guide to help you become an effective code reviewer. Thanks to <a target="_blank" href="https://roadmap.sh/best-practices/code-review">roadmap.sh</a> for the inspiration!</p>
<hr />
<h2 id="heading-before-the-review">Before the review</h2>
<p>Prior to diving in the code changes, gather information about the pull request:</p>
<ul>
<li><p>Read the pull request description. Hopefully the author has included the user story with its purpose and requirements, a list of code changes, and screenshots (if applicable).</p>
</li>
<li><p>Brainstorm and assemble a list of potential bugs or security risks that could get introduced.</p>
</li>
<li><p>Determine the depth in which you should review the code.</p>
</li>
<li><p>Be aware of any relevant documentation that should be updated.</p>
</li>
<li><p>Check your mindset. You are reviewing only for the good of the codebase and the team, not to show off your knowledge or start an unnecessary argument.</p>
</li>
</ul>
<h2 id="heading-during-the-review">During the review</h2>
<p>Now that you have all of the background information, dive into the content of the pull request:</p>
<ul>
<li><p>Validate that the author is targeting the correct branch (this will depend on how your team handles release branches).</p>
</li>
<li><p>Review all changes to ensure that the code change fills the user story requirements. (This step should be completed prior to providing any feedback.)</p>
</li>
<li><p>Be respectful and professional in your feedback. Remember it’s feedback, not criticism.</p>
</li>
<li><p>Consider the overall quality of the code: readability, maintainability, and scalability.</p>
</li>
<li><p>Identify any performance or security concerns.</p>
</li>
<li><p>Ensure that the code change adheres to the project’s coding standards and best practices.</p>
</li>
<li><p>Make sure that the new code is following the style guide set by the organization or team.</p>
</li>
<li><p>For suggestions that does not require a change, add a <em>resolved</em> comment to make the author aware.</p>
</li>
<li><p>If the pull request is large and/or complex, pull the branch and test locally.</p>
</li>
<li><p>If further explanation/discussion is needed, ask the author to set up a meeting.</p>
</li>
</ul>
<h2 id="heading-after-the-review">After the review</h2>
<p>After the initial round of feedbacks, you will need to work with the author to complete the request:</p>
<ul>
<li><p>Consider pair programming if a large or major change is required.</p>
</li>
<li><p>Be open to feedbacks, conflicting opinions, or questions/concerns from the author and be willing to make adjustments.</p>
</li>
<li><p>Resolve conflicting opinions quickly that could prevent the pull request from completing.</p>
</li>
<li><p>Review the updated code to ensure that the suggested changes have been implemented.</p>
</li>
</ul>
]]></content:encoded></item></channel></rss>