<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Architecture on Kinoko's TIL Log</title><link>https://kinoko-tech-blog-theta.vercel.app/tags/architecture/</link><description>Recent content in Architecture on Kinoko's TIL Log</description><generator>Hugo -- gohugo.io</generator><language>en</language><managingEditor>pippimotta@gmail.com (Kinoko)</managingEditor><webMaster>pippimotta@gmail.com (Kinoko)</webMaster><copyright>&amp;copy; Brewed by Kinoko</copyright><lastBuildDate>Wed, 11 Mar 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://kinoko-tech-blog-theta.vercel.app/tags/architecture/index.xml" rel="self" type="application/rss+xml"/><item><title>gRPC Pusher Pattern</title><link>https://kinoko-tech-blog-theta.vercel.app/posts/grpc-pusher-pattern/</link><pubDate>Wed, 11 Mar 2026 00:00:00 +0000</pubDate><author>pippimotta@gmail.com (Kinoko)</author><guid>https://kinoko-tech-blog-theta.vercel.app/posts/grpc-pusher-pattern/</guid><description>&lt;h2 id="the-point"&gt;The Point&lt;/h2&gt;
&lt;p&gt;A gRPC Pusher is a message dispatch intermediary &amp;ndash; it pulls messages from a Pub/Sub subscription and proactively pushes them to a target service&amp;rsquo;s gRPC endpoint. This solves the problem where workers cannot control which consumer processes which message.&lt;/p&gt;
&lt;h2 id="explanation"&gt;Explanation&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Why is this needed?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The testing pain point with worker-based services: a PRRC (PR Review Copy) environment and master share the same subscription. There is no way to guarantee that a test message will be consumed by the PRRC pod rather than a master worker &amp;ndash; so every test requires manually deploying the commit image to master, which is cumbersome.&lt;/p&gt;</description><content:encoded><![CDATA[<h2 id="the-point">The Point</h2>
<p>A gRPC Pusher is a message dispatch intermediary &ndash; it pulls messages from a Pub/Sub subscription and proactively pushes them to a target service&rsquo;s gRPC endpoint. This solves the problem where workers cannot control which consumer processes which message.</p>
<h2 id="explanation">Explanation</h2>
<p><strong>Why is this needed?</strong></p>
<p>The testing pain point with worker-based services: a PRRC (PR Review Copy) environment and master share the same subscription. There is no way to guarantee that a test message will be consumed by the PRRC pod rather than a master worker &ndash; so every test requires manually deploying the commit image to master, which is cumbersome.</p>
<p>The gRPC Pusher solves this as an intermediary:</p>





<pre tabindex="0"><code>Pub/Sub Subscription
        ↓  pull
   gRPC Pusher (intermediary layer)
        ↓  push (can control which endpoint to route to)
  Target Service (specified gRPC endpoint)</code></pre><p>The Pusher centrally pulls messages, then pushes them to a specified endpoint based on configuration &ndash; giving precise control over PRRC traffic without worrying about master workers stealing messages.</p>
<p><strong>Configured via CRD</strong></p>
<p>The Pusher&rsquo;s behavior is managed through Kubernetes CRD config, which can set:</p>
<ul>
<li><strong>Retry policy</strong>: retry strategy after failures (count, backoff)</li>
<li><strong>Traffic limit</strong>: rate limiting for pushes</li>
</ul>
<h2 id="knowledge-sugar">Knowledge Sugar</h2>
<p><strong>Public implementations of this pattern</strong></p>
<p>This &ldquo;pull then push&rdquo; message dispatch pattern is common in the industry:</p>
<ul>
<li><strong>Knative Eventing</strong>: pulls from Broker/Channel, pushes to HTTP/gRPC sink endpoints, supports retry and dead letter sink, configured via CRD</li>
<li><strong>Dapr Pub/Sub</strong>: runs as a sidecar, pulls from various pub/sub backends, pushes to application endpoints via gRPC or HTTP</li>
<li><strong>GCP Push Subscription</strong>: GCP&rsquo;s native push mode, sends messages as HTTP POST to a specified endpoint, supports exponential backoff retry</li>
</ul>
<p><strong>Core design concept: decoupling consume and process</strong></p>
<p>Traditional workers couple &ldquo;pulling messages from a subscription&rdquo; and &ldquo;processing messages&rdquo; in the same process, making traffic routing hard to control. The Pusher separates the two:</p>
<ul>
<li>Pusher handles consume (single entry point)</li>
<li>Target service only handles process (can be any endpoint)</li>
</ul>
<p>This is also the core idea behind <strong>Dapr</strong> and <strong>Knative</strong> &ndash; extracting messaging infrastructure out of application logic.</p>
]]></content:encoded></item><item><title>BFF 101</title><link>https://kinoko-tech-blog-theta.vercel.app/posts/bff101/</link><pubDate>Mon, 02 Mar 2026 00:00:00 +0000</pubDate><author>pippimotta@gmail.com (Kinoko)</author><guid>https://kinoko-tech-blog-theta.vercel.app/posts/bff101/</guid><description>&lt;h2 id="the-point"&gt;The Point&lt;/h2&gt;
&lt;p&gt;BFF (Backend For Frontend) is an architecture pattern where you build a dedicated backend layer for each frontend client, instead of having all clients share a single API.&lt;/p&gt;
&lt;h2 id="explanation"&gt;Explanation&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Why do you need BFF?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Different clients have very different data needs. Take an e-commerce platform as an example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mobile app: small screen, limited bandwidth, needs only a few compact fields&lt;/li&gt;
&lt;li&gt;Web browser: can show richer data, needs more fields&lt;/li&gt;
&lt;li&gt;Third-party partners: yet another set of data format requirements&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With a single shared API, two problems arise:&lt;/p&gt;</description><content:encoded><![CDATA[<h2 id="the-point">The Point</h2>
<p>BFF (Backend For Frontend) is an architecture pattern where you build a dedicated backend layer for each frontend client, instead of having all clients share a single API.</p>
<h2 id="explanation">Explanation</h2>
<p><strong>Why do you need BFF?</strong></p>
<p>Different clients have very different data needs. Take an e-commerce platform as an example:</p>
<ul>
<li>Mobile app: small screen, limited bandwidth, needs only a few compact fields</li>
<li>Web browser: can show richer data, needs more fields</li>
<li>Third-party partners: yet another set of data format requirements</li>
</ul>
<p>With a single shared API, two problems arise:</p>
<ul>
<li><strong>Over-fetching</strong>: returning fields the client does not use</li>
<li><strong>Under-fetching</strong>: one request is not enough, so the client sends multiple requests</li>
</ul>
<p>BFF adds a layer between clients and backend microservices:</p>





<pre tabindex="0"><code>Mobile App  →  Mobile BFF  ┐
Web App     →  Web BFF     ├─→  microservices
Partner API →  Partner BFF ┘</code></pre><p>Each BFF handles:</p>
<ol>
<li>Aggregating responses from multiple microservices (one request instead of many)</li>
<li>Trimming data to the format that specific client needs</li>
<li>Client-specific logic (e.g. mobile pagination)</li>
</ol>
<p><strong>Who maintains the BFF?</strong></p>
<p>Usually the frontend team, so they can adjust the API format on their own without waiting for backend changes.</p>
<h2 id="knowledge-sugar">Knowledge Sugar</h2>
<p><strong>BFF vs API Gateway</strong></p>
<p>These are easy to confuse, but they serve different purposes:</p>
<table>
	<thead>
			<tr>
					<th></th>
					<th>BFF</th>
					<th>API Gateway</th>
			</tr>
	</thead>
	<tbody>
			<tr>
					<td>Purpose</td>
					<td>Trim data for a specific client</td>
					<td>Traffic routing, auth, rate limiting</td>
			</tr>
			<tr>
					<td>Maintained by</td>
					<td>Frontend team</td>
					<td>Platform / infra team</td>
			</tr>
			<tr>
					<td>Count</td>
					<td>One per client type</td>
					<td>Usually one</td>
			</tr>
	</tbody>
</table>
<p>In practice they can coexist &ndash; the API Gateway sits in front handling common concerns, while BFFs sit behind it doing client-specific data aggregation.</p>
<p><strong>When do you not need BFF?</strong></p>
<ul>
<li>Only one client type (e.g. web only)</li>
<li>The backend is a monolith with nothing to aggregate</li>
<li>The team is small and maintaining multiple BFFs costs more than it saves</li>
</ul>
]]></content:encoded></item></channel></rss>