<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
	<channel>
		<title>Hijrah Backend on Faiq Najib</title>
		<link>https://najib.id/en/series/hijrah-backend/</link>
		<description>Recent content in Hijrah Backend on Faiq Najib</description>
		<generator>Hugo</generator>
		<language>en-US</language>
		
		
		
			<copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright>
		
		
			<lastBuildDate>Sun, 25 Oct 2026 20:06:14 +0700</lastBuildDate>
		
			<atom:link href="https://najib.id/en/series/hijrah-backend/index.xml" rel="self" type="application/rss+xml" />
			<item>
				<title>Hijrah Backend (9): Epilogue, MySQL, PostgreSQL, Then MySQL Again</title>
				<link>https://najib.id/en/writing/2026/hijrah-backend-09/</link>
				<pubDate>Thu, 10 Sep 2026 15:30:09 +0700</pubDate>
				<guid>https://najib.id/en/writing/2026/hijrah-backend-09/</guid>
				<description>&lt;p&gt;The series ended in &lt;a href=&#34;https://najib.id/en/writing/2026/hijrah-backend-08/&#34;&gt;the previous episode&lt;/a&gt;. But one story didn&amp;rsquo;t make it into the main run. It happened after I had written almost every other episode. Think of it as a post-credits scene: the screen is dark, the lights are on, and there&amp;rsquo;s one more scene hehe.&lt;/p&gt;&#xA;&lt;p&gt;It&amp;rsquo;s the story of a database engine told to change course twice. I wasn&amp;rsquo;t the one holding the wheel; you can probably guess who was hahaha.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Hijrah Backend (8): Eighteen Months in Retrospect (Give or Take)</title>
				<link>https://najib.id/en/writing/2026/hijrah-backend-08/</link>
				<pubDate>Thu, 10 Sep 2026 15:30:08 +0700</pubDate>
				<guid>https://najib.id/en/writing/2026/hijrah-backend-08/</guid>
				<description>&lt;p&gt;This is the series&amp;rsquo; final episode. The &amp;ldquo;eighteen months&amp;rdquo; in the title needs quotation marks: by the time I wrote this, more time had passed since day one. Oh well, numbers on slides make their own rules. This series has been about that gap from the start hahaha.&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;p&gt;The previous seven episodes covered the technical lessons. In this last part I go through what I&amp;rsquo;d change if I started over, the architecture debt I promised in &lt;a href=&#34;https://najib.id/en/writing/2026/hijrah-backend-02/&#34;&gt;episode two&lt;/a&gt;, a teaching plan that never happened, and what I&amp;rsquo;m grateful for.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Hijrah Backend (7): From TCP Packets to a Time-Series Database</title>
				<link>https://najib.id/en/writing/2026/hijrah-backend-07/</link>
				<pubDate>Thu, 10 Sep 2026 15:30:07 +0700</pubDate>
				<guid>https://najib.id/en/writing/2026/hijrah-backend-07/</guid>
				<description>&lt;p&gt;Every second, the fleet has something to report. Tens of thousands of GPS trackers send TCP packets with positions, ignition status, and signal strength. The system has to take them all in, around the clock, with no &amp;ldquo;please send less data&amp;rdquo; campaign hahaha.&lt;/p&gt;&#xA;&lt;p&gt;In &lt;a href=&#34;https://najib.id/en/writing/2026/hijrah-backend-01/&#34;&gt;episode one&lt;/a&gt; I mentioned that the old system received packets and wrote them to the database in one service. The new setup splits the work: a listener receives and decodes packets, a queue holds them, and a consumer writes them to the database. Here’s how the pieces fit together, plus a mistake or two I made hehe~&lt;/p&gt;</description>
			</item>
			<item>
				<title>Hijrah Backend (6): Tidying a Monolith While the Plane Keeps Flying</title>
				<link>https://najib.id/en/writing/2026/hijrah-backend-06/</link>
				<pubDate>Thu, 10 Sep 2026 15:30:06 +0700</pubDate>
				<guid>https://najib.id/en/writing/2026/hijrah-backend-06/</guid>
				<description>&lt;p&gt;After the migration to Go, one inherited mess was still there: all the repositories were piled into two big folders, &lt;code&gt;repository&lt;/code&gt; and &lt;code&gt;usecase&lt;/code&gt;. Alerts, billing, geofence, fuel, everything was mixed together. The system worked, technically. But finding one house in that city meant knowing every street.&lt;/p&gt;&#xA;&lt;p&gt;In this episode, I reorganized that city into 14 domain modules while keeping the endpoints running in production. Tens of thousands of people use the system, so there was no pause button to press.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Hijrah Backend (5): The Query That Said &#39;Use My Index&#39;</title>
				<link>https://najib.id/en/writing/2026/hijrah-backend-05/</link>
				<pubDate>Thu, 10 Sep 2026 15:30:05 +0700</pubDate>
				<guid>https://najib.id/en/writing/2026/hijrah-backend-05/</guid>
				<description>&lt;p&gt;In &lt;a href=&#34;https://najib.id/en/writing/2026/hijrah-backend-02/&#34;&gt;episode two&lt;/a&gt;, the query was innocent. It took 78 milliseconds in the CLI while the endpoint burned 15 seconds. This time it is the other way around: the query really was guilty. Not because it was complicated, but because one small function wrapper made it &lt;strong&gt;ignore an index that was already there for it&lt;/strong&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-index-was-there-three-times&#34;&gt;The Index Was There, Three Times &lt;a href=&#34;#the-index-was-there-three-times&#34; class=&#34;tdln dimmer&#34;&gt;&lt;small&gt;#&lt;/small&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;The victim: an endpoint counting alerts per device. Its alert table holds tens of millions of rows,&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; and on top of it sits a composite index: (date, device, alert type). Read the endpoint&amp;rsquo;s needs, &amp;ldquo;count alerts per device per type, within a date range&amp;rdquo;, and that index looks like it was built for exactly this query. Someone in the past understood the problem perfectly.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Hijrah Backend (4): Old Code as an Executable Spec</title>
				<link>https://najib.id/en/writing/2026/hijrah-backend-04/</link>
				<pubDate>Thu, 10 Sep 2026 15:30:04 +0700</pubDate>
				<guid>https://najib.id/en/writing/2026/hijrah-backend-04/</guid>
				<description>&lt;p&gt;If I had to boil down the one rule that ran this whole migration, I&amp;rsquo;d say: &lt;strong&gt;the old system is right.&lt;/strong&gt;&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;p&gt;Annoying, I know. You&amp;rsquo;re trusted to move a system to a new language, and rule number one is: change nothing. Not faster, not cleaner, not better. &lt;strong&gt;Identical.&lt;/strong&gt; But after living with it, I get why this anticlimactic rule makes sense.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-the-new-system-must-stay-loyal-to-the-old-one&#34;&gt;Why the New System Must Stay Loyal to the Old One &lt;a href=&#34;#why-the-new-system-must-stay-loyal-to-the-old-one&#34; class=&#34;tdln dimmer&#34;&gt;&lt;small&gt;#&lt;/small&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;Not nostalgia. The reasons are very practical.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Hijrah Backend (3): Porting Dozens of GPS Protocol Parsers Without Stopping the Fleet</title>
				<link>https://najib.id/en/writing/2026/hijrah-backend-03/</link>
				<pubDate>Thu, 10 Sep 2026 15:30:03 +0700</pubDate>
				<guid>https://najib.id/en/writing/2026/hijrah-backend-03/</guid>
				<description>&lt;p&gt;The vehicle was parked, its engine off, but the system read its speed as &lt;strong&gt;66 km/h&lt;/strong&gt;. Satellites were healthy and data kept arriving. After a good while of head-scratching, the cause turned out to be a single character in the parser. One. Character. Hahaha.&lt;/p&gt;&#xA;&lt;h2 id=&#34;rewind-january-2025&#34;&gt;Rewind: January 2025 &lt;a href=&#34;#rewind-january-2025&#34; class=&#34;tdln dimmer&#34;&gt;&lt;small&gt;#&lt;/small&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;As I described in &lt;a href=&#34;https://najib.id/en/writing/2026/hijrah-backend-01/&#34;&gt;episode one&lt;/a&gt;, the migration mandate was waiting before I was hired. One of its biggest tasks was rewriting the protocol parsers, the front door for all fleet data.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Hijrah Backend (2): Anatomy of a 15-Second Endpoint</title>
				<link>https://najib.id/en/writing/2026/hijrah-backend-02/</link>
				<pubDate>Thu, 10 Sep 2026 15:30:02 +0700</pubDate>
				<guid>https://najib.id/en/writing/2026/hijrah-backend-02/</guid>
				<description>&lt;p&gt;In &lt;a href=&#34;https://najib.id/en/writing/2026/hijrah-backend-01/&#34;&gt;the previous episode&lt;/a&gt; I mentioned an endpoint that could take 15 seconds per call. What I remember most wasn&amp;rsquo;t the technical part, but how confident I was in explanations that turned out to be wrong. Ahem.&lt;/p&gt;&#xA;&lt;h2 id=&#34;one-click-then-a-wait&#34;&gt;One Click, Then a Wait &lt;a href=&#34;#one-click-then-a-wait&#34; class=&#34;tdln dimmer&#34;&gt;&lt;small&gt;#&lt;/small&gt;&lt;/a&gt;&lt;/h2&gt;&lt;p&gt;One click on the fuel-estimation-per-vehicle-group endpoint, then a wait of about 17 seconds. If you open that dashboard every day, the wait feels like going back to dial-up.&lt;/p&gt;&#xA;&lt;p&gt;For weeks, the investigation had a soundtrack: &lt;em&gt;&amp;ldquo;Faiq, why is it erroring?&amp;rdquo; &amp;ldquo;Faiq, why is it slow?&amp;rdquo;&lt;/em&gt; Relax, sir, I am tracing it hehe.&lt;/p&gt;</description>
			</item>
			<item>
				<title>Hijrah Backend (1): Day One, Handed a Legacy of 370&#43; Endpoints</title>
				<link>https://najib.id/en/writing/2026/hijrah-backend-01/</link>
				<pubDate>Thu, 10 Sep 2026 15:30:01 +0700</pubDate>
				<guid>https://najib.id/en/writing/2026/hijrah-backend-01/</guid>
				<description>&lt;p&gt;The migration story began before I officially joined the company.&lt;/p&gt;&#xA;&lt;p&gt;At a GPS tracking company in Surabaya, Indonesia, one of the team&amp;rsquo;s seniors received a mandate to rewrite the existing system. To this day I don&amp;rsquo;t know exactly what was said in that internal meeting; I only know the outcome: they decided to move to Go. And only after that decision was final did the job opening appear.&lt;/p&gt;&#xA;&lt;p&gt;So my position in the hiring process was a little unusual: I wasn&amp;rsquo;t there to help choose the project&amp;rsquo;s direction. I was there to carry out a decision other people had already made.&lt;/p&gt;</description>
			</item>
	</channel>
</rss>
