<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Tohru Yaginuma</title>
    <description>The latest articles on DEV Community by Tohru Yaginuma (@tohru_yaginuma_4f041533c6).</description>
    <link>https://dev.to/tohru_yaginuma_4f041533c6</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4070197%2Fde54a3d2-386e-4e56-9ace-97700c7acafa.jpg</url>
      <title>DEV Community: Tohru Yaginuma</title>
      <link>https://dev.to/tohru_yaginuma_4f041533c6</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tohru_yaginuma_4f041533c6"/>
    <language>en</language>
    <item>
      <title>Using the Grok API to Reduce the Effort of Keeping Up with AI</title>
      <dc:creator>Tohru Yaginuma</dc:creator>
      <pubDate>Sat, 19 Sep 2026 02:45:05 +0000</pubDate>
      <link>https://dev.to/tohru_yaginuma_4f041533c6/using-the-grok-api-to-reduce-the-effort-of-keeping-up-with-ai-3edk</link>
      <guid>https://dev.to/tohru_yaginuma_4f041533c6/using-the-grok-api-to-reduce-the-effort-of-keeping-up-with-ai-3edk</guid>
      <description>&lt;h2&gt;
  
  
  Long Story Short
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;X is useful for keeping up with AI and tech, but I find browsing the feed mentally exhausting.&lt;/li&gt;
&lt;li&gt;I built a simple pipeline with Grok API, Google Apps Script, and Message App that sends me a few selected AI topics every morning.&lt;/li&gt;
&lt;li&gt;The most important part was not collecting more information, but defining what information was actually worth sending to me.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;I am very sensitive to information, and X is one of the social platforms I struggle with the most.&lt;/p&gt;

&lt;p&gt;Reading the feed can leave me surprisingly drained.&lt;/p&gt;

&lt;p&gt;In particular, if I accidentally open the "For you" tab and start scrolling through posts from people I do not follow, I sometimes notice that it affects my mood for a while afterward.&lt;/p&gt;

&lt;p&gt;At the same time, X is still one of the most useful places for me to keep up with fast-moving information.&lt;/p&gt;

&lt;p&gt;This is especially true for AI and software engineering.&lt;/p&gt;

&lt;p&gt;New tools, coding-agent workflows, experiments, failures, pricing changes, and practical tips often appear there before they are summarized elsewhere.&lt;/p&gt;

&lt;p&gt;So I had a problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I wanted information from X, but I did not want to spend time inside X.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I had been thinking for a while about whether I could separate those two things.&lt;/p&gt;

&lt;p&gt;Then I learned that Grok could help with exactly that.&lt;/p&gt;

&lt;p&gt;It could access information from X, summarize it, filter it, and be called through an API.&lt;/p&gt;

&lt;p&gt;That was enough for me to start building something the same day.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;The pipeline is very simple.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;X
↓
Grok API
↓
Google Apps Script
↓
Message App (LINE in my case)
↓
Me
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Google Apps Script runs on a schedule every morning.&lt;/p&gt;

&lt;p&gt;It calls Grok and asks for a small number of AI-related topics from roughly the previous 24 hours.&lt;/p&gt;

&lt;p&gt;The selected topics are then sent to LINE, which is the messaging app I already use every day.&lt;/p&gt;

&lt;p&gt;So instead of opening X and searching for useful information, I wake up and find a short list already waiting for me.&lt;/p&gt;

&lt;p&gt;Grok is mainly doing two things:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Collecting information from X&lt;/li&gt;
&lt;li&gt;Selecting which information is worth showing me&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The second part turned out to be much more important than I initially expected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Grok Was a Good Fit
&lt;/h2&gt;

&lt;p&gt;I did not only need search.&lt;/p&gt;

&lt;p&gt;I wanted something that could:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;access information being discussed on X&lt;/li&gt;
&lt;li&gt;summarize what happened&lt;/li&gt;
&lt;li&gt;compare multiple topics&lt;/li&gt;
&lt;li&gt;filter out things I probably would not care about&lt;/li&gt;
&lt;li&gt;run automatically through an API&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wanted to reduce a large stream of information into a very small number of things that were actually relevant to my work.&lt;/p&gt;

&lt;h2&gt;
  
  
  The First Version Wasn't Very Useful
&lt;/h2&gt;

&lt;p&gt;My first prompt was much simpler.&lt;/p&gt;

&lt;p&gt;I basically asked for important AI news.&lt;/p&gt;

&lt;p&gt;Technically, it worked.&lt;/p&gt;

&lt;p&gt;The problem was that "important AI news" was much broader than what I actually wanted.&lt;/p&gt;

&lt;p&gt;I started getting topics that were academically interesting or technologically impressive, but not especially useful for my daily work as a software engineer.&lt;/p&gt;

&lt;p&gt;There is a lot happening in AI.&lt;/p&gt;

&lt;p&gt;Research papers, benchmarks, model releases, image generation, business news, funding, robotics, policy, and many other areas can all reasonably be called "AI news."&lt;/p&gt;

&lt;p&gt;But that was not what I was trying to optimize for.&lt;/p&gt;

&lt;p&gt;What I really wanted was something closer to:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What happened in AI recently that might change how a software engineer works?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That distinction changed the prompt significantly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Hard Part Was Selection
&lt;/h2&gt;

&lt;p&gt;Over time, I started making the selection criteria much more explicit.&lt;/p&gt;

&lt;p&gt;I now prioritize topics around things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;coding agents&lt;/li&gt;
&lt;li&gt;agentic software engineering&lt;/li&gt;
&lt;li&gt;developer tools&lt;/li&gt;
&lt;li&gt;MCP&lt;/li&gt;
&lt;li&gt;CLI and IDE workflows&lt;/li&gt;
&lt;li&gt;debugging&lt;/li&gt;
&lt;li&gt;testing&lt;/li&gt;
&lt;li&gt;code review&lt;/li&gt;
&lt;li&gt;CI/CD&lt;/li&gt;
&lt;li&gt;model changes that affect software development&lt;/li&gt;
&lt;li&gt;practical AI adoption inside engineering teams&lt;/li&gt;
&lt;li&gt;real-world experiments from engineers and maintainers&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also started prioritizing posts that contain concrete experience.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many tokens did it use?&lt;/li&gt;
&lt;li&gt;How long did it take?&lt;/li&gt;
&lt;li&gt;How much did it cost?&lt;/li&gt;
&lt;li&gt;Did it actually work?&lt;/li&gt;
&lt;li&gt;What failed?&lt;/li&gt;
&lt;li&gt;How much engineering time did it save?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I find these much more useful than generic announcements because they give me something I can compare with my own work.&lt;/p&gt;

&lt;p&gt;One of the questions I now effectively ask the model is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If a software engineer only had five minutes to catch up on AI today, would this be worth reading?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Another is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Would this make someone want to reply with their own experience?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Those questions improved the output much more than simply adding more AI-related keywords.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed for Me
&lt;/h2&gt;

&lt;p&gt;The amount of effort required to keep up with AI has gone down quite a bit.&lt;/p&gt;

&lt;p&gt;Before, catching up meant opening X, looking through the feed, deciding what was relevant, opening posts, and trying not to get distracted by everything else.&lt;/p&gt;

&lt;p&gt;Now the default is much simpler.&lt;/p&gt;

&lt;p&gt;I open my messaging app and read a few selected topics.&lt;/p&gt;

&lt;p&gt;If something looks genuinely interesting, I can then open the original source.&lt;/p&gt;

&lt;p&gt;Of course, directly browsing X would still expose me to more information.&lt;/p&gt;

&lt;p&gt;I am probably missing useful posts.&lt;/p&gt;

&lt;p&gt;But that is a trade-off I am comfortable with.&lt;/p&gt;

&lt;p&gt;The goal of this system is not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Never miss anything.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Keep learning about AI consistently without making information gathering exhausting.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For me, that is much more sustainable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;p&gt;This system is not a complete replacement for X.&lt;/p&gt;

&lt;p&gt;The model can miss important information.&lt;/p&gt;

&lt;p&gt;Its selection is influenced by the prompt.&lt;/p&gt;

&lt;p&gt;A topic that would have been useful to me may never be selected.&lt;/p&gt;

&lt;p&gt;And because AI is such a broad field, getting the filtering criteria right still requires iteration.&lt;/p&gt;

&lt;p&gt;I have already rewritten the prompt several times, and I expect to keep changing it as my interests and work change.&lt;/p&gt;

&lt;p&gt;There is also an unavoidable element of randomness in what reaches me each day.&lt;/p&gt;

&lt;p&gt;I think that is acceptable.&lt;/p&gt;

&lt;p&gt;I would rather receive a small imperfect selection consistently than have access to everything and avoid looking at it altogether.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The technology behind this project is not particularly complicated.&lt;/p&gt;

&lt;p&gt;It is mostly an API, a scheduled Google Apps Script, and a messaging app.&lt;/p&gt;

&lt;p&gt;But I enjoyed building it because it solved a very specific problem I had in my daily life.&lt;/p&gt;

&lt;p&gt;I did not want a better X client.&lt;/p&gt;

&lt;p&gt;I wanted to remove the part of X that was difficult for me while keeping the part that was useful.&lt;/p&gt;

&lt;p&gt;The result was a small information pipeline tailored to how I actually want to consume information.&lt;/p&gt;

&lt;p&gt;It also reminded me of something I like about software engineering:&lt;/p&gt;

&lt;p&gt;Not every useful system has to solve a large problem.&lt;/p&gt;

&lt;p&gt;Sometimes it is enough to notice a small source of friction in your own life and build something that makes it a little easier.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>automation</category>
      <category>productivity</category>
    </item>
    <item>
      <title>I Started Using /clear After Testing with Playwright MCP</title>
      <dc:creator>Tohru Yaginuma</dc:creator>
      <pubDate>Fri, 11 Sep 2026 23:07:45 +0000</pubDate>
      <link>https://dev.to/tohru_yaginuma_4f041533c6/i-started-using-clear-after-testing-with-playwright-mcp-5ggk</link>
      <guid>https://dev.to/tohru_yaginuma_4f041533c6/i-started-using-clear-after-testing-with-playwright-mcp-5ggk</guid>
      <description>&lt;h2&gt;
  
  
  Long Story Short
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;After using tools like Playwright MCP that can return large tool results, continuing to work with that context still in the session can make subsequent processing heavier.&lt;/li&gt;
&lt;li&gt;Since then, when I finish testing with Playwright MCP and do not need that context for the next task, I use &lt;code&gt;/clear&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;My rule is simple: &lt;strong&gt;“Will I need this context for the next task?”&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;Recently, I hit the usage credits limit in Claude Code, which I use at work.&lt;/p&gt;

&lt;p&gt;What confused me was that my plan usage still had plenty of room, while the additional usage credits I had configured had already reached their limit.&lt;/p&gt;

&lt;p&gt;After looking into it, I realized that Fable usage was what had caused me to go beyond the included usage and consume additional credits.&lt;/p&gt;

&lt;p&gt;That explained why the credits had run out.&lt;/p&gt;

&lt;p&gt;But it also made me ask a different question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Why was I consuming so much usage in the first place?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Until then, I had been using Claude Code every day without paying much attention to what was actually driving my usage.&lt;/p&gt;

&lt;p&gt;So I started looking more closely at &lt;code&gt;/usage&lt;/code&gt; and reviewing how I had been working.&lt;/p&gt;

&lt;p&gt;One thing that stood out was Playwright MCP.&lt;/p&gt;

&lt;p&gt;That did not mean Playwright MCP itself was the reason I had exceeded my usage limit.&lt;/p&gt;

&lt;p&gt;Rather, it made me notice how much context could accumulate during browser testing, and how that context could continue to affect subsequent work if I kept using the same session.&lt;/p&gt;

&lt;p&gt;The habit I eventually changed was very simple:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After finishing a test with Playwright MCP, if I do not need that context for the next task, I use &lt;code&gt;/clear&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This article is a short learning log about how I got there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Usage Is Not Just About How Many Times You Talk to Claude
&lt;/h2&gt;

&lt;p&gt;I used to think about Claude Code usage in a fairly simple way:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The more questions I ask, the more expensive it gets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is not entirely wrong.&lt;/p&gt;

&lt;p&gt;But the size of the context Claude is working with also matters.&lt;/p&gt;

&lt;p&gt;Claude Code is not looking only at the latest sentence I type.&lt;/p&gt;

&lt;p&gt;It works with the context needed for the current task, including previous conversation history, files it has read, and tool results.&lt;/p&gt;

&lt;p&gt;So, if I simplify my understanding quite a bit:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The larger the context is, the heavier it can become to keep processing within that context.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;/usage&lt;/code&gt; Made Me Look at Playwright MCP
&lt;/h2&gt;

&lt;p&gt;When I checked &lt;code&gt;/usage&lt;/code&gt;, I saw results like these:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;79% of your usage was at &amp;gt;150k context

61% of your usage came from subagent-heavy sessions

36% of your usage came from the MCP server "playwright"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first, I thought these were three separate problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;My context was too large&lt;/li&gt;
&lt;li&gt;I was using too many subagents&lt;/li&gt;
&lt;li&gt;Playwright MCP was expensive&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But after looking at how I had been working, they seemed more connected than I initially thought.&lt;/p&gt;

&lt;p&gt;When using Playwright MCP for E2E checks, I repeatedly do things like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open a page&lt;/li&gt;
&lt;li&gt;Inspect elements&lt;/li&gt;
&lt;li&gt;Click a button&lt;/li&gt;
&lt;li&gt;Fill in a form&lt;/li&gt;
&lt;li&gt;Check the state after navigation&lt;/li&gt;
&lt;li&gt;Fix something and try again if necessary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For Claude to understand the browser state, relatively large tool results can be added to the context during these interactions.&lt;/p&gt;

&lt;p&gt;Each individual operation may feel like a simple browser check.&lt;/p&gt;

&lt;p&gt;But after repeating them several times, browser-related context can accumulate quickly.&lt;/p&gt;

&lt;p&gt;That part can be considered a necessary cost of testing.&lt;/p&gt;

&lt;p&gt;The more interesting problem for me was what happened afterward.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Test Was Finished, but the Context Wasn't
&lt;/h2&gt;

&lt;p&gt;From my perspective, once I reach:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Test complete. Time to move on to the next task.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;much of the information generated during the Playwright session has already served its purpose.&lt;/p&gt;

&lt;p&gt;But if I continue using the same session, I also continue working with that context.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Implement a feature&lt;/li&gt;
&lt;li&gt;Verify it with Playwright MCP&lt;/li&gt;
&lt;li&gt;Confirm that it works&lt;/li&gt;
&lt;li&gt;Start implementing another feature&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;I used to move directly to step 4 without resetting the session.&lt;/p&gt;

&lt;p&gt;But when working on the next feature, I may no longer need all the browser information generated during the previous E2E test.&lt;/p&gt;

&lt;p&gt;There is a gap between:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“This context is no longer useful to me”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;“Claude Code is no longer carrying this context.”&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Looking into my usage made me much more aware of that difference.&lt;/p&gt;

&lt;h2&gt;
  
  
  After Playwright MCP Testing, I Use &lt;code&gt;/clear&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;So I now follow one simple rule:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;After finishing a Playwright MCP test, if I do not need that context for the next task, I use &lt;code&gt;/clear&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I do not clear the session mechanically after every test.&lt;/p&gt;

&lt;p&gt;My rule is simply:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Will I need this context for the next task?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If not, I clear it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;When I first started using Claude Code, I tended to think of context as something that was simply better to have more of.&lt;/p&gt;

&lt;p&gt;And of course, having the right context is important.&lt;/p&gt;

&lt;p&gt;But after looking into my usage, I started thinking about the cost of keeping context that is no longer useful.&lt;/p&gt;

&lt;p&gt;This feels especially relevant with tools like Playwright MCP, where repeated browser interactions can add a lot of information to the session in a relatively short period of time.&lt;/p&gt;

&lt;p&gt;And once the test is finished, that information may no longer be useful for the next task.&lt;/p&gt;

&lt;p&gt;This experience made me start thinking of Claude Code context as having a kind of lifecycle:&lt;/p&gt;

&lt;p&gt;Collect it when needed.&lt;/p&gt;

&lt;p&gt;Keep it while it is useful.&lt;/p&gt;

&lt;p&gt;Let it go when its job is done.&lt;/p&gt;

&lt;p&gt;For now, that is the rule I am following.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>webdev</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
    <item>
      <title>Web APIs and Batch Jobs Communicate Failure Differently</title>
      <dc:creator>Tohru Yaginuma</dc:creator>
      <pubDate>Sat, 22 Aug 2026 23:58:22 +0000</pubDate>
      <link>https://dev.to/tohru_yaginuma_4f041533c6/web-apis-and-batch-jobs-communicate-failure-differently-2mga</link>
      <guid>https://dev.to/tohru_yaginuma_4f041533c6/web-apis-and-batch-jobs-communicate-failure-differently-2mga</guid>
      <description>&lt;h2&gt;
  
  
  Long Story Short
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Web APIs can communicate failure through HTTP status codes, but batch jobs need to terminate in a way that allows the execution environment to recognize that the process has failed.&lt;/li&gt;
&lt;li&gt;In this case, I changed the error handling to throw an exception. This caused failed Lambda invocations to be reflected in the CloudWatch &lt;code&gt;Errors&lt;/code&gt; metric, which allowed the alarm to trigger.&lt;/li&gt;
&lt;li&gt;Error handling does not end inside the application. We also need to think about whether failures can be correctly observed by the monitoring and alerting systems outside it.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;Recently, I had the opportunity to implement a mechanism that sends a Slack notification when a batch job running on AWS fails.&lt;/p&gt;

&lt;p&gt;The batch job itself was an existing Lambda function that was already running in production, so I initially thought the task would be relatively simple.&lt;/p&gt;

&lt;p&gt;The setup was to monitor Lambda execution errors with CloudWatch and send notifications to Slack through AWS notification services.&lt;/p&gt;

&lt;p&gt;The AWS-side configuration itself was not particularly complicated.&lt;/p&gt;

&lt;p&gt;However, when I looked at the existing batch code that we wanted to monitor, I found a problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Error Was Happening, but the Job Wasn't Failing
&lt;/h2&gt;

&lt;p&gt;The existing error handling included code like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return false
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return { status: 500 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The intention was probably to indicate that an error had occurred.&lt;/p&gt;

&lt;p&gt;From Lambda's perspective, however, that is not what happens.&lt;/p&gt;

&lt;p&gt;Returning &lt;code&gt;false&lt;/code&gt; or &lt;code&gt;{ status: 500 }&lt;/code&gt; simply means that the Lambda function returned a value and completed successfully.&lt;/p&gt;

&lt;p&gt;Just because the returned value contains the number &lt;code&gt;500&lt;/code&gt; does not mean that Lambda automatically treats the invocation as a failure.&lt;/p&gt;

&lt;p&gt;As a result, even though the application code intended to handle the situation as an error, the execution environment still saw it as a successful invocation.&lt;/p&gt;

&lt;p&gt;Because of that, the invocation was not treated as a function error and was not reflected in CloudWatch's &lt;code&gt;Errors&lt;/code&gt; metric.&lt;/p&gt;

&lt;p&gt;The CloudWatch Alarm therefore did not trigger, and no Slack notification was sent.&lt;/p&gt;

&lt;p&gt;Building the monitoring mechanism made me realize that the existing error handling was not communicating the failure correctly to the systems outside the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  I Couldn't Apply the Same Mental Model as a Web API
&lt;/h2&gt;

&lt;p&gt;What I found interesting was the difference between how Web APIs and batch jobs communicate failure.&lt;/p&gt;

&lt;p&gt;In a Web API, we use HTTP status codes to communicate the result of a request to the client.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;HTTP 500 Internal Server Error
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By returning an HTTP 500 response, the client can recognize that the request has failed.&lt;/p&gt;

&lt;p&gt;When you spend a lot of time working with Web APIs, it becomes natural to think:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If something goes wrong, return 500.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But what I was working with this time was not a Web API responding to an HTTP request. It was a batch job running on Lambda.&lt;/p&gt;

&lt;p&gt;There was no client waiting for an HTTP response.&lt;/p&gt;

&lt;p&gt;What mattered was not returning a value that contained &lt;code&gt;500&lt;/code&gt;, but &lt;strong&gt;making the Lambda invocation itself fail&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In this case, I refactored the code to throw an exception when an error occurred:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;throw new Error(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This caused the Lambda invocation itself to fail, which was then reflected in the CloudWatch &lt;code&gt;Errors&lt;/code&gt; metric.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error Handling Doesn't End Inside the Application
&lt;/h2&gt;

&lt;p&gt;When I started this task, I thought I was simply adding a Slack notification for batch failures.&lt;/p&gt;

&lt;p&gt;But once I followed the notification flow back to the existing code, I ended up asking a more fundamental question:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Is this application actually communicating its failures correctly to the outside world?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Writing an error log.&lt;/p&gt;

&lt;p&gt;Returning &lt;code&gt;false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Returning a value containing &lt;code&gt;500&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you only look at the application code, all of these can appear to be forms of error handling.&lt;/p&gt;

&lt;p&gt;But if the Lambda runtime and CloudWatch cannot observe the execution as a failure, that error handling does not connect to monitoring or alerting.&lt;/p&gt;

&lt;p&gt;This experience made me realize that when thinking about error handling, I should consider not only:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"How is the error handled inside the code?"&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;but also:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;"Who needs to observe this failure, and how will they know that it happened?"&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Web APIs communicate success and failure to clients through HTTP status codes.&lt;/p&gt;

&lt;p&gt;Batch jobs are different. We need to think about how the execution environment determines whether a job succeeded or failed.&lt;/p&gt;

&lt;p&gt;Implementing this Slack notification mechanism made me realize that the familiar Web API mindset of "return 500 when something fails" cannot simply be applied to batch jobs.&lt;/p&gt;

&lt;p&gt;Error handling is not only an application-level concern.&lt;/p&gt;

&lt;p&gt;I learned that part of error handling is also making sure that a failure can be correctly observed by the execution environment and the monitoring systems around the application.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>aws</category>
      <category>monitoring</category>
    </item>
    <item>
      <title>Designing HTML Page Caching Changed How I Think About Caching</title>
      <dc:creator>Tohru Yaginuma</dc:creator>
      <pubDate>Sun, 16 Aug 2026 15:09:34 +0000</pubDate>
      <link>https://dev.to/tohru_yaginuma_4f041533c6/designing-html-page-caching-changed-how-i-think-about-caching-4k8f</link>
      <guid>https://dev.to/tohru_yaginuma_4f041533c6/designing-html-page-caching-changed-how-i-think-about-caching-4k8f</guid>
      <description>&lt;h2&gt;
  
  
  Long Story Short
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Designing HTML page caching in practice connected several concepts I had previously understood separately, such as TTL, browser caching, and where cache policies should live.&lt;/li&gt;
&lt;li&gt;In our architecture, where HTML pages are cached with CloudFront, the choice between CSR and SSR also affects whether data can benefit from the HTML cache.&lt;/li&gt;
&lt;li&gt;Starting from the simple goal of “caching pages” made me think more broadly about what should be cached and where, including API responses and backend caching.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;Recently, I had the opportunity to design HTML page caching for a web platform at work.&lt;/p&gt;

&lt;p&gt;It was my first time designing HTML page caching in practice, and we used AWS CloudFront as our CDN.&lt;/p&gt;

&lt;p&gt;I already had a basic understanding of caching.&lt;/p&gt;

&lt;p&gt;Store a response once, reuse it later, reduce server-side processing, and improve response times.&lt;/p&gt;

&lt;p&gt;At least conceptually, I thought I understood it.&lt;/p&gt;

&lt;p&gt;The task also seemed relatively simple at first.&lt;/p&gt;

&lt;p&gt;If we cache HTML pages in CloudFront, requests don’t need to reach the application every time.&lt;/p&gt;

&lt;p&gt;Then we just need to decide which pages to cache and how long their TTLs should be.&lt;/p&gt;

&lt;p&gt;Once I actually started working on the design, however, I realized there was more to think about.&lt;/p&gt;

&lt;h2&gt;
  
  
  Looking at CSR and SSR Through the Lens of Caching
&lt;/h2&gt;

&lt;p&gt;One of the things I found particularly interesting was the relationship between CSR, SSR, and HTML page caching.&lt;/p&gt;

&lt;p&gt;I had previously thought about CSR and SSR mainly in terms of where rendering happens.&lt;/p&gt;

&lt;p&gt;With CSR, rendering happens in the browser. With SSR, HTML is generated on the server.&lt;/p&gt;

&lt;p&gt;From there, I would usually think about things like SEO and initial page-load performance.&lt;/p&gt;

&lt;p&gt;None of that was new to me.&lt;/p&gt;

&lt;p&gt;But designing HTML page caching gave me another perspective on CSR and SSR.&lt;/p&gt;

&lt;p&gt;In our case, CloudFront caches HTML pages.&lt;/p&gt;

&lt;p&gt;This means that when data is fetched during SSR and included in the HTML, the resulting HTML — including that data — can be served from the CloudFront cache.&lt;/p&gt;

&lt;p&gt;With CSR, on the other hand, the browser fetches data from an API after receiving the HTML. That data is therefore outside the HTML page cache.&lt;/p&gt;

&lt;p&gt;Of course, this doesn’t mean that “SSR is cacheable” and “CSR is not.”&lt;/p&gt;

&lt;p&gt;SSR-generated HTML doesn’t have to be cached, and API responses fetched through CSR can be cached at other layers.&lt;/p&gt;

&lt;p&gt;But in our architecture, the choice between CSR and SSR affects whether that data can benefit from the HTML page cache.&lt;/p&gt;

&lt;p&gt;I had previously viewed CSR and SSR primarily as rendering strategies, so seeing this connection in practice was interesting to me.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caching Exists Beyond HTML
&lt;/h2&gt;

&lt;p&gt;Thinking about CSR led me to another question:&lt;/p&gt;

&lt;p&gt;What about the API responses fetched by the client?&lt;/p&gt;

&lt;p&gt;For this project, the scope was HTML page caching with CloudFront. I hadn't really considered API response caching as part of the same problem at that point.&lt;/p&gt;

&lt;p&gt;But while thinking about CSR and SSR, I realized that API responses can also be cached at different layers, such as a CDN or the backend itself.&lt;/p&gt;

&lt;p&gt;That made me realize that I had been thinking about caching too narrowly, mostly in terms of HTML pages.&lt;/p&gt;

&lt;p&gt;Do we cache the HTML?&lt;/p&gt;

&lt;p&gt;Do we cache API responses?&lt;/p&gt;

&lt;p&gt;Do we cache something in the browser?&lt;/p&gt;

&lt;p&gt;At the CDN?&lt;/p&gt;

&lt;p&gt;On the backend?&lt;/p&gt;

&lt;p&gt;They are all forms of caching, but each comes with different considerations.&lt;/p&gt;

&lt;p&gt;I didn’t design API caching as part of this project.&lt;/p&gt;

&lt;p&gt;Still, thinking about HTML page caching made me look beyond HTML and think more deeply about caching across the system. That itself was an important learning for me.&lt;/p&gt;

&lt;h2&gt;
  
  
  TTL Needs a Reason Too
&lt;/h2&gt;

&lt;p&gt;TTL was another area I hadn’t thought deeply about until I had to design it myself.&lt;/p&gt;

&lt;p&gt;A longer TTL allows a cached response to be reused for longer.&lt;/p&gt;

&lt;p&gt;But it also means that stale content can remain visible for longer after the underlying page has been updated.&lt;/p&gt;

&lt;p&gt;Not every page has the same traffic or update frequency either.&lt;/p&gt;

&lt;p&gt;Some pages receive a lot of traffic but rarely change. Others may change relatively frequently.&lt;/p&gt;

&lt;p&gt;Once I started thinking about actual pages, I realized that TTL wasn’t simply a matter of choosing a “long” or “short” value.&lt;/p&gt;

&lt;p&gt;It was a trade-off involving how fresh each page needed to be.&lt;/p&gt;

&lt;p&gt;I used to think of TTL mostly as a configuration value. This experience made me realize that the value itself should have a reason behind it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Should Caching Decisions Live?
&lt;/h2&gt;

&lt;p&gt;Another question was where the decision about which pages to cache should live.&lt;/p&gt;

&lt;p&gt;We could define rules in CloudFront based on URLs and other conditions.&lt;/p&gt;

&lt;p&gt;But the application often has the most context about whether a particular page is safe to cache.&lt;/p&gt;

&lt;p&gt;In our design, we decided to keep information about cacheable pages on the application side and use that information to control caching behavior in CloudFront.&lt;/p&gt;

&lt;p&gt;Before this project, I partly thought of HTML page caching as CDN configuration.&lt;/p&gt;

&lt;p&gt;Working on the design made me realize that it can also be an application design question:&lt;/p&gt;

&lt;p&gt;Where should the responsibility for caching decisions live?&lt;/p&gt;

&lt;h2&gt;
  
  
  A Clearer Mental Model of Caching
&lt;/h2&gt;

&lt;p&gt;I don’t feel that I learned one particular new caching technology from this experience.&lt;/p&gt;

&lt;p&gt;The bigger learning was that concepts I had previously understood separately started to connect.&lt;/p&gt;

&lt;p&gt;CSR and SSR.&lt;/p&gt;

&lt;p&gt;CDNs.&lt;/p&gt;

&lt;p&gt;TTL.&lt;/p&gt;

&lt;p&gt;Browser caching.&lt;/p&gt;

&lt;p&gt;API response caching.&lt;/p&gt;

&lt;p&gt;Backend caching.&lt;/p&gt;

&lt;p&gt;I already knew these terms and concepts individually.&lt;/p&gt;

&lt;p&gt;But designing HTML page caching myself forced me to think about them in terms of a real system: What should we do here?&lt;/p&gt;

&lt;p&gt;The questions I ask about caching have also changed.&lt;/p&gt;

&lt;p&gt;What are we caching?&lt;/p&gt;

&lt;p&gt;Where are we caching it?&lt;/p&gt;

&lt;p&gt;Who can safely share the cached response?&lt;/p&gt;

&lt;p&gt;How fresh does it need to be?&lt;/p&gt;

&lt;p&gt;There is still plenty I don’t know.&lt;/p&gt;

&lt;p&gt;But I now have a much clearer idea of what questions I should be asking.&lt;/p&gt;

&lt;p&gt;Designing HTML page caching gave me a much clearer mental model of caching than I had before.&lt;/p&gt;

</description>
      <category>cloudfront</category>
      <category>webdev</category>
      <category>architecture</category>
      <category>web</category>
    </item>
    <item>
      <title>Async-First Doesn’t Mean Async-Only</title>
      <dc:creator>Tohru Yaginuma</dc:creator>
      <pubDate>Sun, 09 Aug 2026 20:27:34 +0000</pubDate>
      <link>https://dev.to/tohru_yaginuma_4f041533c6/async-first-doesnt-mean-async-only-ebm</link>
      <guid>https://dev.to/tohru_yaginuma_4f041533c6/async-first-doesnt-mean-async-only-ebm</guid>
      <description>&lt;h2&gt;
  
  
  Key Takeaways
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Asynchronous discussions can lose momentum because participants are focused on different tasks. For complex or important topics, it’s often better to switch to synchronous communication.&lt;/li&gt;
&lt;li&gt;At least in my experience working in a Japanese-speaking organization, AI-generated messages are often still too verbose to send as-is. As writing becomes cheaper, it’s even more important to reduce the cognitive load on readers.&lt;/li&gt;
&lt;li&gt;Async-first does not mean async-only. Keeping written records while introducing short meetings when necessary can reduce the overall cost of communication.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Context
&lt;/h2&gt;

&lt;p&gt;I currently work from Vancouver, Canada, for a fully remote and fully flexible organization based in Japan.&lt;/p&gt;

&lt;p&gt;Since everyone works on their own schedule, much of our day-to-day communication, decision-making, and discussion happens asynchronously.&lt;/p&gt;

&lt;p&gt;There are many benefits to this way of working. People can think at their own pace, and discussions naturally leave a written record.&lt;/p&gt;

&lt;p&gt;As someone who is fairly introverted, I also appreciate having time to think through my ideas before sharing them.&lt;/p&gt;

&lt;p&gt;Recently, however, I’ve started to realize that keeping every discussion asynchronous is not always the most efficient approach.&lt;/p&gt;

&lt;h2&gt;
  
  
  Complex discussions are expensive to read
&lt;/h2&gt;

&lt;p&gt;When discussing multiple options, I usually start by sharing my recommendation, then document the reasoning behind it and the pros and cons of alternative approaches.&lt;/p&gt;

&lt;p&gt;The more complicated the topic becomes, the longer the document becomes.&lt;/p&gt;

&lt;p&gt;Writing requires effort, but so does reading. Someone has to understand the background, process the trade-offs, form an opinion, and respond.&lt;/p&gt;

&lt;p&gt;Lately, I’ve become more aware of the reader’s cost than the writer’s.&lt;/p&gt;

&lt;p&gt;In our company, Japanese is the shared language, and much of our written communication is now assisted by AI. While AI makes it easier to produce long documents, the resulting text can still be unnecessarily verbose or difficult to follow.&lt;/p&gt;

&lt;p&gt;AI makes writing cheaper. It does not necessarily make reading cheaper.&lt;/p&gt;

&lt;p&gt;On top of that, everyone already has their own priorities.&lt;/p&gt;

&lt;p&gt;When a message arrives, people are often in the middle of something else. Replies become spread out over hours or days. Discussions can lose momentum, and important but non-urgent topics may eventually fade away without reaching a conclusion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Write first, then talk
&lt;/h2&gt;

&lt;p&gt;To address this, I’ve started scheduling short meetings whenever a discussion becomes too complex to resolve asynchronously.&lt;/p&gt;

&lt;p&gt;This doesn’t mean abandoning written communication.&lt;/p&gt;

&lt;p&gt;I still document the background, context, and available options. AI helps me draft these documents quickly, but I always review and simplify them before sharing.&lt;/p&gt;

&lt;p&gt;Once everyone has the necessary context, a short meeting allows the team to focus on the same problem at the same time.&lt;/p&gt;

&lt;p&gt;I’ve found that questions that would otherwise require many rounds of messages can often be resolved in just a few minutes of conversation.&lt;/p&gt;

&lt;p&gt;There’s another benefit as well.&lt;/p&gt;

&lt;p&gt;In a fully remote, fully flexible environment, opportunities to talk to teammates naturally become less frequent. Even when the purpose is purely technical, real-time conversations can help build mutual understanding and trust.&lt;/p&gt;

&lt;h2&gt;
  
  
  Async-first doesn’t mean avoiding meetings
&lt;/h2&gt;

&lt;p&gt;I used to believe that if a team was designed around asynchronous communication, then most discussions should stay asynchronous.&lt;/p&gt;

&lt;p&gt;I don’t think that anymore.&lt;/p&gt;

&lt;p&gt;Asynchronous communication is a tool, not the goal.&lt;/p&gt;

&lt;p&gt;If a topic is simple, asynchronous communication works well. If a discussion becomes complex, stalls, or requires multiple rounds of clarification, a short synchronous conversation can be the more efficient option.&lt;/p&gt;

&lt;p&gt;I’ve learned not to hesitate to schedule a meeting when it helps move an important discussion forward.&lt;/p&gt;

&lt;p&gt;Being async-first doesn’t mean avoiding synchronous communication.&lt;/p&gt;

&lt;p&gt;It means choosing the communication style that minimizes the overall cost for the team.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>remote</category>
      <category>productivity</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
