<?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: Sanudin</title>
    <description>The latest articles on DEV Community by Sanudin (@sanudin-dev).</description>
    <link>https://dev.to/sanudin-dev</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%2F3760854%2Fd3829bce-f434-4f4c-a857-ce8b6eca446a.png</url>
      <title>DEV Community: Sanudin</title>
      <link>https://dev.to/sanudin-dev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sanudin-dev"/>
    <language>en</language>
    <item>
      <title>Meta Tag HTML — Catatan Pribadi</title>
      <dc:creator>Sanudin</dc:creator>
      <pubDate>Wed, 12 Aug 2026 15:40:33 +0000</pubDate>
      <link>https://dev.to/sanudin-dev/meta-tag-html-catatan-pribadi-48e4</link>
      <guid>https://dev.to/sanudin-dev/meta-tag-html-catatan-pribadi-48e4</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🌐 Baca artikel ini dalam Bahasa Inggris di &lt;a href="https://dev.to/sanudin-dev/html-meta-tags-my-reference-notes-35l7"&gt;sini&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Saya selalu mencari-cari lagi hal ini setiap memulai proyek baru, jadi ini tempat untuk mengumpulkan semuanya jadi satu — lengkap dengan catatan singkat &lt;em&gt;kenapa&lt;/em&gt; masing-masing penting, supaya di masa depan tidak perlu memikirkan ulang dari nol.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lompat ke:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pengaturan Dasar Dokumen dan Responsif&lt;/li&gt;
&lt;li&gt;SEO dan Indexing Dasar&lt;/li&gt;
&lt;li&gt;Social Card (OG + X)&lt;/li&gt;
&lt;li&gt;GEO / AI Crawler&lt;/li&gt;
&lt;li&gt;Header Keamanan&lt;/li&gt;
&lt;li&gt;PWA / Browser&lt;/li&gt;
&lt;li&gt;Tabel Referensi&lt;/li&gt;
&lt;li&gt;Yang Saya Pakai&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Pengaturan Dasar Dokumen dan Responsif
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;charset="UTF-8"&lt;/code&gt; — harus berada di bagian atas &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;. Jika browser menemukan byte non-ASCII sebelum menemukan deklarasi charset, dokumen bisa saja di-parse ulang dari awal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;viewport&lt;/code&gt; — tanpa ini, tampilan mobile hanya menampilkan layout desktop yang di-zoom out. Wajib, selalu disertakan.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  SEO dan Indexing Dasar
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"robots"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"index, follow"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://sanudin.dev/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt; — cuplikan yang muncul di bawah link pada hasil pencarian, sekitar 150–160 karakter. Tidak langsung memengaruhi ranking, tapi memengaruhi click-through rate.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;robots&lt;/code&gt; — defaultnya sudah &lt;code&gt;index, follow&lt;/code&gt;, jadi tag ini hanya perlu dipasang jika saya ingin sebaliknya (&lt;code&gt;noindex, nofollow&lt;/code&gt; pada rute staging).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;canonical&lt;/code&gt; — menunjuk ke URL "asli" ketika konten yang sama bisa diakses lewat beberapa URL (trailing slash, query parameter, dan sejenisnya).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Social Card (OG + X)
&lt;/h2&gt;

&lt;p&gt;Open Graph adalah standar universal untuk preview card di Facebook, LinkedIn, Discord, dan Slack. X menggunakan fallback ke OG kecuali saya menambahkan tag &lt;code&gt;twitter:*&lt;/code&gt; secara khusus.&lt;/p&gt;

&lt;p&gt;Ukuran gambar yang perlu diingat: &lt;strong&gt;1200×630px&lt;/strong&gt; (rasio 1.91:1).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Sanudin | Software Engineer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Backend-first software engineer writing about web development, from Indonesia."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://sanudin.dev/og-cover.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://sanudin.dev/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:site_name"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Sanudin"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:width"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"1200"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:height"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"630"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Sanudin | Software Engineer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Backend-first software engineer writing about web development, from Indonesia."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://sanudin.dev/og-cover.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pengingat: &lt;code&gt;og:type&lt;/code&gt; sebaiknya &lt;code&gt;article&lt;/code&gt; untuk halaman blog post, sementara &lt;code&gt;website&lt;/code&gt; hanya untuk homepage atau landing page.&lt;/p&gt;




&lt;h2&gt;
  
  
  GEO / AI Crawler
&lt;/h2&gt;

&lt;p&gt;Ada dua tempat terpisah untuk mengatur hal ini — meta tag (level halaman) dan robots.txt (level situs).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"robots"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"noai, noimageai"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;GPTBot&lt;/span&gt;
&lt;span class="n"&gt;Disallow&lt;/span&gt;: /

&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;ClaudeBot&lt;/span&gt;
&lt;span class="n"&gt;Disallow&lt;/span&gt;: /

&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;Googlebot&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Catatan untuk diri sendiri: &lt;code&gt;noai&lt;/code&gt;/&lt;code&gt;noimageai&lt;/code&gt; bukan tag standar resmi (bermula dari DeviantArt, 2022) — adopsinya masih tidak merata. robots.txt adalah yang benar-benar berpengaruh jika saya peduli soal pemblokiran AI training.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON-LD untuk identitas — kenapa ini penting
&lt;/h3&gt;

&lt;p&gt;Blok ini bukan untuk manusia, melainkan untuk search engine dan sistem AI yang mencoba mengenali &lt;em&gt;siapa&lt;/em&gt; yang sedang berbicara. Halaman yang penuh teks "Saya Sanudin, software engineer" adalah sesuatu yang harus mereka simpulkan sendiri; blok JSON-LD langsung menyatakannya sebagai fakta terstruktur.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Person&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sanudin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jobTitle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Software Engineer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://sanudin.dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sameAs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://github.com/sanudin-dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://linkedin.com/in/sanudin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;knowsAbout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TypeScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Node.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PHP&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Web Development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@type: "Person"&lt;/code&gt; — menandai ini secara spesifik sebagai data &lt;em&gt;tentang sebuah entitas&lt;/em&gt;, bukan sekadar konten halaman. Ini yang membedakan search engine menebak-nebak siapa penulisnya dengan diberi tahu secara langsung.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sameAs&lt;/code&gt; — field inilah yang benar-benar bekerja. Field ini yang memungkinkan search engine atau sistem AI menghubungkan "Sanudin di GitHub," "Sanudin di LinkedIn," dan "Sanudin di sanudin.dev" sebagai &lt;em&gt;orang yang sama&lt;/em&gt;, bukan tiga sebutan yang tidak berhubungan. Tanpa array ini, setiap profil menjadi pulau tersendiri.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jobTitle&lt;/code&gt; — perlu sama persis dengan wording bio kanonik saya ("Software Engineer," bukan sinonimnya). Konsistensi di semua profil itulah yang sebenarnya membangun asosiasi entitas ini — jika tidak cocok, justru berlawanan dengan tujuan blok ini.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;knowsAbout&lt;/code&gt; — sinyal topik, bukan keyword stuffing. Harus benar-benar merefleksikan apa yang didukung oleh konten situs, kalau tidak hanya menjadi noise.&lt;/li&gt;
&lt;li&gt;Sebelum publish: periksa lewat Google Rich Results Test atau schema.org validator. JSON-LD gagalnya diam-diam — kesalahan penulisan hanya akan diabaikan, bukan memunculkan error yang akan saya sadari.&lt;/li&gt;
&lt;li&gt;Ini adalah schema &lt;em&gt;identitas situs&lt;/em&gt;. Jika nanti ingin setiap post memiliki structured data sendiri, itu tipe &lt;code&gt;Article&lt;/code&gt; terpisah dengan field &lt;code&gt;author&lt;/code&gt; yang menunjuk kembali ke &lt;code&gt;Person&lt;/code&gt; ini — tambahan untuk nanti, bukan sesuatu yang perlu dikerjakan sekarang.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Header Keamanan
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Content Security Policy — fungsi masing-masing bagiannya
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"Content-Security-Policy"&lt;/span&gt;
      &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"default-src 'self'; script-src 'self' https://trustedscripts.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;default-src 'self'&lt;/code&gt; — baseline: tidak ada yang boleh dimuat kecuali dari origin yang sama. Setiap directive di bawah ini adalah pengecualian dari aturan ini.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;script-src 'self' https://trustedscripts.com&lt;/code&gt; — hanya script milik saya sendiri dan satu domain yang di-whitelist ini yang boleh berjalan. Ini directive yang benar-benar penting untuk menghentikan script hasil injeksi/XSS — fakta bahwa saya tidak menambahkan &lt;code&gt;'unsafe-inline'&lt;/code&gt; di sini adalah bagian pentingnya, bukan kelalaian.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;style-src 'self' 'unsafe-inline'&lt;/code&gt; — &lt;code&gt;'unsafe-inline'&lt;/code&gt; di sini adalah trade-off yang nyata, bukan default yang bisa diabaikan begitu saja. Diperlukan karena banyak framework menyuntikkan &lt;code&gt;style=""&lt;/code&gt; saat runtime, tapi ini memang melemahkan proteksi terhadap inline style hasil injeksi (ada teknik CSS-based UI-redress/exfiltration nyata yang memanfaatkan celah ini). Risikonya jauh lebih kecil dibanding jika ini dipasang pada &lt;code&gt;script-src&lt;/code&gt;, tapi jika suatu saat ingin menutup celah ini, solusinya adalah nonce atau hash per blok style, bukan sekadar menghapus directive-nya.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;img-src 'self' data: https:&lt;/code&gt; — &lt;code&gt;data:&lt;/code&gt; mengizinkan gambar base64 inline (ikon kecil, placeholder), &lt;code&gt;https:&lt;/code&gt; mengizinkan gambar dari domain HTTPS mana pun secara luas sehingga tidak perlu mempertahankan daftar allowlist untuk setiap domain gambar.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pengingat soal keterbatasan lewat meta tag: &lt;code&gt;frame-ancestors&lt;/code&gt;, &lt;code&gt;report-uri&lt;/code&gt;/&lt;code&gt;report-to&lt;/code&gt;, dan &lt;code&gt;sandbox&lt;/code&gt; tidak berfungsi jika CSP diatur lewat &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; — hanya bisa lewat HTTP header sesungguhnya. Alasannya soal timing: proteksi-proteksi spesifik itu harus sudah aktif &lt;em&gt;sebelum&lt;/em&gt; halaman mulai memuat apa pun, dan meta tag yang berada di dalam HTML sudah terlambat untuk itu. Versi meta ini adalah fallback untuk kondisi di mana saya tidak memiliki kendali atas header server (static hosting), bukan pengganti penuh.&lt;/p&gt;

&lt;h3&gt;
  
  
  Referrer Policy — apa yang sebenarnya dikirim oleh &lt;code&gt;strict-origin-when-cross-origin&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"referrer"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"strict-origin-when-cross-origin"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rincian apa yang sebenarnya dilakukan value ini, karena "strict-origin-when-cross-origin" tidak menjelaskan dirinya sendiri:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Request same-origin → mengirim URL lengkap (path + query string).&lt;/li&gt;
&lt;li&gt;Request cross-origin, tapi level keamanan protokol sama (https → https) → hanya mengirim origin-nya (scheme + host), bukan path-nya.&lt;/li&gt;
&lt;li&gt;Request downgrade (https → http) → tidak mengirim apa pun.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Kenapa ini penting: tanpa ini, mengklik link keluar bisa membocorkan path internal dan query string situs ke situs tujuan link tersebut. Catatan untuk diri sendiri: sebagian besar browser modern sekarang sudah default ke kebijakan ini secara persis, jadi tag ini lebih soal eksplisit dan berjaga-jaga jika default-nya berubah (atau ada policy lain yang diatur di tempat lain yang berkonflik) daripada benar-benar wajib hari ini.&lt;/p&gt;

&lt;p&gt;Value lain yang perlu diingat jika membutuhkan yang lebih ketat atau lebih longgar: &lt;code&gt;no-referrer&lt;/code&gt; (tidak mengirim apa pun sama sekali — paling privat, tapi bisa mengganggu analytics atau alur auth berbasis referrer), &lt;code&gt;same-origin&lt;/code&gt; (tidak ada yang cross-origin sama sekali), &lt;code&gt;unsafe-url&lt;/code&gt; (selalu mengirim URL lengkap — sebaiknya dihindari, paling banyak bocor).&lt;/p&gt;




&lt;h2&gt;
  
  
  PWA / Browser
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"theme-color"&lt;/span&gt; &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"(prefers-color-scheme: light)"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"#ffffff"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"theme-color"&lt;/span&gt; &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"(prefers-color-scheme: dark)"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"#09090b"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mewarnai UI chrome browser itu sendiri (address bar mobile, kartu task-switcher OS) agar sesuai dengan halaman. Dua deklarasi karena &lt;code&gt;prefers-color-scheme&lt;/code&gt; adalah media query — satu tag tanpa itu akan memakai warna yang sama terlepas dari tema sistem.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"mobile-web-app-capable"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"apple-mobile-web-app-status-bar-style"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"black-translucent"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"apple-mobile-web-app-title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Sanudin"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mobile-web-app-capable&lt;/code&gt; — membuat halaman masuk ke standalone mode (tanpa URL bar, tanpa navigasi browser) saat dibuka dari home screen. Ini tag yang sekarang berlaku, tanpa prefix — Chrome DevTools sekarang secara aktif menandai &lt;code&gt;apple-mobile-web-app-capable&lt;/code&gt; yang lama sebagai deprecated dan meminta beralih ke versi ini. Safari secara historis hanya mengenali versi apple-prefixed, jadi mungkin masih perlu keduanya untuk iOS lama — perlu dicek ulang dukungan Safari terkini sebelum benar-benar meninggalkan tag lama. Selain itu: mulai iOS 26, Safari sekarang secara default membuat semua situs yang ditambahkan ke home screen langsung terbuka dalam mode web-app, sehingga tag ini pengaruhnya lebih kecil di iOS dibanding sebelumnya.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apple-mobile-web-app-status-bar-style&lt;/code&gt; — masih Apple-only, belum ada pengganti standar. &lt;code&gt;black-translucent&lt;/code&gt; membuat konten halaman bisa scroll edge-to-edge di bawah status bar; &lt;code&gt;default&lt;/code&gt;/&lt;code&gt;black&lt;/code&gt; mempertahankan bar yang solid.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apple-mobile-web-app-title&lt;/code&gt; — juga masih Apple-specific, mengatur label di bawah ikon home screen. Pendekatan modernnya adalah mengatur ini lewat &lt;code&gt;name&lt;/code&gt;/&lt;code&gt;short_name&lt;/code&gt; di manifest.json — tag meta ini dipertahankan sebagai fallback karena Safari tidak selalu membaca nama dari manifest secara konsisten.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Catatan yang lebih besar untuk diri sendiri: panduan resmi saat ini (Chrome/web.dev) adalah lebih mengandalkan Web App Manifest untuk semua ini dalam jangka panjang, bukan meta tag-meta tag ini — mereka sudah ada sebelum spesifikasi manifest dan bisa menghasilkan fallback behavior yang lebih buruk jika manifest gagal dimuat. Anggap semua di atas sebagai lapisan kompatibilitas praktis, bukan kondisi ideal.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"manifest"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/manifest.json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"apple-touch-icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/icons/apple-icon-180.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"any"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/icon.svg"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/svg+xml"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ini fondasi sebenarnya — manifest.json adalah tempat name, icons, start_url, display mode, dan theme color seharusnya berada ke depannya. &lt;code&gt;apple-touch-icon&lt;/code&gt; tetap dipisah sebagai link karena Safari memperlakukannya sebagai override, bukan membaca icon dari manifest secara konsisten.&lt;/p&gt;




&lt;h2&gt;
  
  
  Tabel Referensi
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Fungsi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;charset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Encoding karakter yang benar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;viewport&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rendering responsif di mobile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Teks cuplikan SERP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;robots&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Instruksi index/crawl&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;canonical&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Menghindari masalah duplicate-content&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;og:*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview card (FB, LinkedIn, Discord)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;twitter:*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview card di X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;robots: noai, noimageai&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sinyal opt-out AI training (sukarela)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;robots.txt&lt;/code&gt; (GPTBot, dll)&lt;/td&gt;
&lt;td&gt;Blokir AI crawler level situs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON-LD (&lt;code&gt;Person&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Data identitas terstruktur untuk AI/search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Content-Security-Policy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Membatasi sumber script/style/media yang diizinkan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;referrer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mengontrol data referrer yang keluar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;theme-color&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Warna chrome browser mobile&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mobile-web-app-capable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mode standalone (tag yang berlaku sekarang)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apple-mobile-web-app-*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Perilaku home screen khusus iOS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;manifest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kemampuan install PWA&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Yang Saya Pakai
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Selalu:&lt;/strong&gt; charset, viewport, description, canonical, og:&lt;em&gt;/twitter:&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setelah dasarnya beres:&lt;/strong&gt; robots (hanya jika benar-benar butuh noindex), theme-color, tag PWA, CSP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Situasional, dicek ulang jika relevan:&lt;/strong&gt; tag GEO, JSON-LD.&lt;/p&gt;




&lt;p&gt;Originally published at: &lt;a href="https://sanudin.dev/blog/html-meta-tags-reference" rel="noopener noreferrer"&gt;HTML Meta Tags: My Reference Notes&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>webdev</category>
      <category>security</category>
      <category>seo</category>
    </item>
    <item>
      <title>HTML Meta Tags: My Reference Notes</title>
      <dc:creator>Sanudin</dc:creator>
      <pubDate>Wed, 12 Aug 2026 15:30:50 +0000</pubDate>
      <link>https://dev.to/sanudin-dev/html-meta-tags-my-reference-notes-35l7</link>
      <guid>https://dev.to/sanudin-dev/html-meta-tags-my-reference-notes-35l7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🌐 Read this post in Bahasa Indonesia &lt;a href="https://dev.to/sanudin-dev/meta-tag-html-catatan-pribadi-48e4"&gt;here&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;I keep re-looking these up every time I start a new project, so this is where I'm dumping them all in one place — with a short note on &lt;em&gt;why&lt;/em&gt; each one matters, so future-me doesn't have to re-derive it from scratch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Jump to:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Document Core and Responsive Setup&lt;/li&gt;
&lt;li&gt;Basic SEO and Indexing&lt;/li&gt;
&lt;li&gt;Social Cards (OG + X)&lt;/li&gt;
&lt;li&gt;GEO / AI Crawlers&lt;/li&gt;
&lt;li&gt;Security Headers&lt;/li&gt;
&lt;li&gt;PWA / Browser&lt;/li&gt;
&lt;li&gt;Quick Table&lt;/li&gt;
&lt;li&gt;What I Actually Use&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Document Core and Responsive Setup
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1.0"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;charset="UTF-8"&lt;/code&gt; — needs to sit near the top of &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt;, or the browser can end up re-parsing the whole doc if it hits non-ASCII bytes first.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;viewport&lt;/code&gt; — without it, mobile just renders the desktop layout zoomed way out. Non-negotiable, always include.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Basic SEO and Indexing
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"..."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"robots"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"index, follow"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"canonical"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"https://sanudin.dev/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;description&lt;/code&gt; — the snippet under my link in search results, ~150–160 chars. Doesn't move ranking directly, but affects click-through.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;robots&lt;/code&gt; — default is already &lt;code&gt;index, follow&lt;/code&gt;, so I only need this tag when I want the opposite (&lt;code&gt;noindex, nofollow&lt;/code&gt; on staging routes).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;canonical&lt;/code&gt; — points to the "real" URL when the same content is reachable multiple ways (trailing slash, query params, etc).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Social Cards (OG + X)
&lt;/h2&gt;

&lt;p&gt;Open Graph = the universal standard for FB/LinkedIn/Discord/Slack preview cards. X falls back to OG unless I add &lt;code&gt;twitter:*&lt;/code&gt; tags specifically.&lt;/p&gt;

&lt;p&gt;Image size to remember: &lt;strong&gt;1200×630px&lt;/strong&gt; (1.91:1 ratio).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:type"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"website"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Sanudin | Software Engineer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Backend-first software engineer writing about web development, from Indonesia."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://sanudin.dev/og-cover.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:url"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://sanudin.dev/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:site_name"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Sanudin"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:width"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"1200"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;property=&lt;/span&gt;&lt;span class="s"&gt;"og:image:height"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"630"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:card"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"summary_large_image"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Sanudin | Software Engineer"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:description"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Backend-first software engineer writing about web development, from Indonesia."&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"twitter:image"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"https://sanudin.dev/og-cover.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reminder: &lt;code&gt;og:type&lt;/code&gt; should be &lt;code&gt;article&lt;/code&gt; on blog posts, &lt;code&gt;website&lt;/code&gt; is only for the homepage/landing pages.&lt;/p&gt;




&lt;h2&gt;
  
  
  GEO / AI Crawlers
&lt;/h2&gt;

&lt;p&gt;Two separate places to control this — meta tag (page-level) and robots.txt (site-wide).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"robots"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"noai, noimageai"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight conf"&gt;&lt;code&gt;&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;GPTBot&lt;/span&gt;
&lt;span class="n"&gt;Disallow&lt;/span&gt;: /

&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;ClaudeBot&lt;/span&gt;
&lt;span class="n"&gt;Disallow&lt;/span&gt;: /

&lt;span class="n"&gt;User&lt;/span&gt;-&lt;span class="n"&gt;agent&lt;/span&gt;: &lt;span class="n"&gt;Googlebot&lt;/span&gt;
&lt;span class="n"&gt;Allow&lt;/span&gt;: /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note to self: &lt;code&gt;noai&lt;/code&gt;/&lt;code&gt;noimageai&lt;/code&gt; isn't an official spec tag (started at DeviantArt, 2022) — adoption is spotty at best. robots.txt is the one that actually does something if I care about blocking AI training.&lt;/p&gt;

&lt;h3&gt;
  
  
  JSON-LD for identity — why I bother with this
&lt;/h3&gt;

&lt;p&gt;This block isn't for humans, it's for search engines and AI systems trying to figure out &lt;em&gt;who&lt;/em&gt; is talking. A page full of prose saying "I'm Sanudin, a software engineer" is something they have to infer; a JSON-LD block just states it as structured fact.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"application/ld+json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@context&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://schema.org&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Person&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Sanudin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;jobTitle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Software Engineer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;url&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://sanudin.dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sameAs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://github.com/sanudin-dev&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://linkedin.com/in/sanudin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;knowsAbout&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;TypeScript&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Next.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Node.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;PHP&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Web Development&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@type: "Person"&lt;/code&gt; — marks this specifically as data &lt;em&gt;about an entity&lt;/em&gt;, not just page content. This is the difference between search engines guessing at who wrote something vs. being told directly.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sameAs&lt;/code&gt; — this is the field doing the real work. It's what lets a search engine or AI system connect "Sanudin on GitHub," "Sanudin on LinkedIn," and "Sanudin on sanudin.dev" as &lt;em&gt;the same person&lt;/em&gt; instead of three unrelated mentions. Without this array, every profile is an island.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jobTitle&lt;/code&gt; — needs to match my canonical bio wording exactly ("Software Engineer," not a synonym). Consistency across every profile is literally what builds the entity association — a mismatch works against the whole point of this block.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;knowsAbout&lt;/code&gt; — a topical signal, not keyword stuffing. Should genuinely reflect what the site's content backs up, or it's just noise.&lt;/li&gt;
&lt;li&gt;Before publishing: run it through Google's Rich Results Test or the schema.org validator. JSON-LD fails silently — a typo just gets ignored rather than throwing an error I'd notice.&lt;/li&gt;
&lt;li&gt;This is &lt;em&gt;site identity&lt;/em&gt; schema. If I want individual posts to carry their own structured data later, that's a separate &lt;code&gt;Article&lt;/code&gt; type with an &lt;code&gt;author&lt;/code&gt; field pointing back to this &lt;code&gt;Person&lt;/code&gt; — a future addition, not something I need to retrofit now.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Security Headers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Content Security Policy — what each part is actually doing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;http-equiv=&lt;/span&gt;&lt;span class="s"&gt;"Content-Security-Policy"&lt;/span&gt;
      &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"default-src 'self'; script-src 'self' https://trustedscripts.com; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:;"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;default-src 'self'&lt;/code&gt; — the baseline: nothing loads unless it's same-origin. Every other directive below is an exception to this.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;script-src 'self' https://trustedscripts.com&lt;/code&gt; — only my own scripts and this one whitelisted domain can execute. This is the directive that actually matters for stopping injected/XSS scripts — the fact that I haven't added &lt;code&gt;'unsafe-inline'&lt;/code&gt; here is the important part, not an oversight.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;style-src 'self' 'unsafe-inline'&lt;/code&gt; — &lt;code&gt;'unsafe-inline'&lt;/code&gt; here is a real trade-off, not a default I should ignore. It's needed because a lot of frameworks inject &lt;code&gt;style=""&lt;/code&gt; at runtime, but it does weaken protection against injected inline styles specifically (there are real CSS-based UI-redress/exfiltration tricks that rely on exactly this). Much smaller risk than allowing it on &lt;code&gt;script-src&lt;/code&gt;, but if I ever want to close this gap, the fix is nonces or hashes per style block, not just removing the directive.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;img-src 'self' data: https:&lt;/code&gt; — &lt;code&gt;data:&lt;/code&gt; allows base64-inlined images (small icons, placeholders), &lt;code&gt;https:&lt;/code&gt; broadly allows images from any HTTPS source so I'm not maintaining an allowlist of every image domain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reminder on the meta-tag limitation: &lt;code&gt;frame-ancestors&lt;/code&gt;, &lt;code&gt;report-uri&lt;/code&gt;/&lt;code&gt;report-to&lt;/code&gt;, and &lt;code&gt;sandbox&lt;/code&gt; don't work when CSP is set via &lt;code&gt;&amp;lt;meta&amp;gt;&lt;/code&gt; — only via an actual HTTP header. The reason is timing: those specific protections need to be enforced &lt;em&gt;before&lt;/em&gt; the page starts loading anything, and a meta tag sitting inside the HTML is already too late for that. This meta version is a fallback for when I don't control server headers (static hosting), not a full substitute.&lt;/p&gt;

&lt;h3&gt;
  
  
  Referrer Policy — what &lt;code&gt;strict-origin-when-cross-origin&lt;/code&gt; actually sends
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"referrer"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"strict-origin-when-cross-origin"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Breaking down what this value actually does, since "strict-origin-when-cross-origin" doesn't explain itself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Same-origin request → sends the full URL (path + query string).&lt;/li&gt;
&lt;li&gt;Cross-origin request, but same protocol security level (https → https) → sends only the origin (scheme + host), not the path.&lt;/li&gt;
&lt;li&gt;Downgrade request (https → http) → sends nothing at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Why this matters: without it, clicking an outbound link can leak my site's internal paths and query strings to whatever site the link points to. Note to self: most modern browsers already default to this exact policy now, so this tag is more about being explicit and guarding against a future default change (or another policy set elsewhere conflicting) than strictly necessary today.&lt;/p&gt;

&lt;p&gt;Other values worth remembering if I need something stricter or looser: &lt;code&gt;no-referrer&lt;/code&gt; (send nothing, ever — most private, but can break analytics or referrer-based auth flows), &lt;code&gt;same-origin&lt;/code&gt; (nothing at all cross-origin), &lt;code&gt;unsafe-url&lt;/code&gt; (always send the full URL — avoid, leaks the most).&lt;/p&gt;




&lt;h2&gt;
  
  
  PWA / Browser
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"theme-color"&lt;/span&gt; &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"(prefers-color-scheme: light)"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"#ffffff"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"theme-color"&lt;/span&gt; &lt;span class="na"&gt;media=&lt;/span&gt;&lt;span class="s"&gt;"(prefers-color-scheme: dark)"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"#09090b"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Colors the browser's own UI chrome (mobile address bar, OS task-switcher card) to match the page. Two declarations because &lt;code&gt;prefers-color-scheme&lt;/code&gt; is a media query — a single tag without it would apply the same color regardless of system theme.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"mobile-web-app-capable"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"yes"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"apple-mobile-web-app-status-bar-style"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"black-translucent"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"apple-mobile-web-app-title"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"Sanudin"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;mobile-web-app-capable&lt;/code&gt; — puts the page into standalone mode (no URL bar, no browser nav) when launched from the home screen. This is the current, unprefixed tag — Chrome DevTools actively flags the old &lt;code&gt;apple-mobile-web-app-capable&lt;/code&gt; as deprecated now and asks for this version instead. Safari historically only recognized the apple-prefixed one, so I may still need both for older iOS — worth rechecking current Safari support before dropping the legacy tag entirely. Also: as of iOS 26, Safari defaults every home-screen-added site to open in web-app mode regardless, so this tag matters less on iOS than it used to.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apple-mobile-web-app-status-bar-style&lt;/code&gt; — still Apple-only, no standardized replacement exists yet. &lt;code&gt;black-translucent&lt;/code&gt; lets page content scroll edge-to-edge under the status bar; &lt;code&gt;default&lt;/code&gt;/&lt;code&gt;black&lt;/code&gt; keep a solid bar instead.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;apple-mobile-web-app-title&lt;/code&gt; — also still Apple-specific, controls the label under the home screen icon. The modern approach is to set this via &lt;code&gt;name&lt;/code&gt;/&lt;code&gt;short_name&lt;/code&gt; in manifest.json instead — keeping this meta tag around as a fallback since Safari doesn't always read the manifest name reliably.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Bigger note to self: the actual current guidance (Chrome/web.dev) is to lean on the Web App Manifest for all of this long-term, not these meta tags — they predate the manifest spec and can produce worse fallback behavior if the manifest fails to load. Treat everything above as a practical compatibility layer, not the ideal end state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"manifest"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/manifest.json"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"apple-touch-icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/icons/apple-icon-180.png"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/favicon.ico"&lt;/span&gt; &lt;span class="na"&gt;sizes=&lt;/span&gt;&lt;span class="s"&gt;"any"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"icon"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"/icon.svg"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"image/svg+xml"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the actual foundation — manifest.json is where name, icons, start_url, display mode, and theme colors are meant to live going forward. &lt;code&gt;apple-touch-icon&lt;/code&gt; stays as a separate link because Safari treats it as an override rather than reliably reading icons from the manifest.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Table
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tag&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;charset&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Correct character encoding&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;viewport&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Responsive mobile rendering&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;description&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;SERP snippet text&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;robots&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Index/crawl instructions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;canonical&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Avoid duplicate-content issues&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;og:*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview cards (FB, LinkedIn, Discord)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;twitter:*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Preview cards on X&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;robots: noai, noimageai&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Voluntary AI-training opt-out signal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;robots.txt&lt;/code&gt; (GPTBot, etc.)&lt;/td&gt;
&lt;td&gt;Site-wide AI crawler blocking&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JSON-LD (&lt;code&gt;Person&lt;/code&gt;)&lt;/td&gt;
&lt;td&gt;Structured identity data for AI/search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Content-Security-Policy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Restrict allowed script/style/media sources&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;referrer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Control outbound referrer data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;theme-color&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mobile browser chrome color&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;mobile-web-app-capable&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Standalone launch mode (current tag)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;apple-mobile-web-app-*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;iOS-specific home screen behavior&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;manifest&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;PWA installability&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  What I Actually Use
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Always:&lt;/strong&gt; charset, viewport, description, canonical, og:&lt;em&gt;/twitter:&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Once the basics are set:&lt;/strong&gt; robots (only when I actually need noindex), theme-color, PWA tags, CSP.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Situational, revisit if it matters that day:&lt;/strong&gt; GEO tags, JSON-LD.&lt;/p&gt;




&lt;p&gt;Originally published at: &lt;a href="https://sanudin.dev/blog/html-meta-tags-reference" rel="noopener noreferrer"&gt;HTML Meta Tags: My Reference Notes&lt;/a&gt;&lt;/p&gt;

</description>
      <category>html</category>
      <category>webdev</category>
      <category>security</category>
      <category>seo</category>
    </item>
    <item>
      <title>Git &amp; Collaboration: A Beginner's Guide (With Real Analogies)</title>
      <dc:creator>Sanudin</dc:creator>
      <pubDate>Mon, 08 Jun 2026 00:39:41 +0000</pubDate>
      <link>https://dev.to/sanudin-dev/git-collaboration-a-beginners-guide-with-real-analogies-4oh7</link>
      <guid>https://dev.to/sanudin-dev/git-collaboration-a-beginners-guide-with-real-analogies-4oh7</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🌐 Read this post in Bahasa Indonesia &lt;a href="https://dev.to/sanudin-dev/git-kolaborasi-panduan-untuk-pemula-lengkap-dengan-analogi-56ch"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📝 A note on this article&lt;/strong&gt;&lt;br&gt;
This post is based on my personal study notes. The ideas, learning journey, and understanding are mine — I used AI to help structure and expand them into a proper blog format form.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Learning Git doesn't have to be intimidating. In this article, I'll break down the essential concepts of version control and collaboration — using simple analogies that anyone can understand.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Is Git?
&lt;/h2&gt;

&lt;p&gt;Git is a &lt;strong&gt;version control system&lt;/strong&gt;. Think of it as a save system for your code — like save points in a video game. Every time you save (commit), Git remembers the state of your project at that moment. If something goes wrong, you can always go back.&lt;/p&gt;




&lt;h2&gt;
  
  
  Repository: Your Project's Warehouse
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;repository&lt;/strong&gt; (or "repo") is the folder that Git watches. There are two types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local repository&lt;/strong&gt;: lives on your computer. Your personal workspace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remote repository&lt;/strong&gt;: lives on a server (GitHub, GitLab, Bitbucket). The "official" shared copy your team can access.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;They stay connected through a Remote URL, so you can push your local changes up and pull others' changes down.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init                            &lt;span class="c"&gt;# Start tracking a folder&lt;/span&gt;
git remote add origin &amp;lt;url&amp;gt;         &lt;span class="c"&gt;# Connect to a remote repo&lt;/span&gt;
git push origin main                &lt;span class="c"&gt;# Send commits to remote&lt;/span&gt;
git pull origin main                &lt;span class="c"&gt;# Get latest from remote&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Commit: Your Project's Save Point
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;commit&lt;/strong&gt; is a snapshot of your project at a specific moment. Each commit has:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A message describing what changed&lt;/li&gt;
&lt;li&gt;A unique ID (hash)&lt;/li&gt;
&lt;li&gt;A timestamp
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;                           &lt;span class="c"&gt;# Stage all changes&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add homepage layout"&lt;/span&gt; &lt;span class="c"&gt;# Save a snapshot&lt;/span&gt;
git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;                   &lt;span class="c"&gt;# View commit history&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Write meaningful commit messages. Future you will thank present you.&lt;/p&gt;




&lt;h2&gt;
  
  
  Checkout, Reset, Revert: Traveling Through Time
&lt;/h2&gt;

&lt;p&gt;These three commands all interact with your commit history — but in very different ways:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;git checkout&lt;/code&gt; — Visit the Past (Temporarily)
&lt;/h3&gt;

&lt;p&gt;Like a time traveler with a visitor's pass. You can look around at an old commit without changing anything permanently.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &amp;lt;commit-hash&amp;gt;          &lt;span class="c"&gt;# Visit an old commit&lt;/span&gt;
git checkout main                   &lt;span class="c"&gt;# Go back to the present&lt;/span&gt;
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; new-branch &amp;lt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;   &lt;span class="c"&gt;# Start a new branch from old commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;git reset&lt;/code&gt; — Erase History
&lt;/h3&gt;

&lt;p&gt;Goes back to a past commit and &lt;strong&gt;removes&lt;/strong&gt; everything that came after. Use with care — especially if you've already pushed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset &lt;span class="nt"&gt;--soft&lt;/span&gt; HEAD~1             &lt;span class="c"&gt;# Undo last commit, keep changes staged&lt;/span&gt;
git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; HEAD~1             &lt;span class="c"&gt;# Undo last commit, delete changes too&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;git revert&lt;/code&gt; — The Safe Undo
&lt;/h3&gt;

&lt;p&gt;Creates a &lt;strong&gt;new commit&lt;/strong&gt; that reverses a previous one. History stays intact — the safest option when working on a shared repo.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git revert &amp;lt;commit-hash&amp;gt;            &lt;span class="c"&gt;# Undo a commit safely&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Rule of thumb: if you've already pushed, use &lt;code&gt;revert&lt;/code&gt;. If you haven't, &lt;code&gt;reset&lt;/code&gt; is fine.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Branches: Parallel Universes for Your Code
&lt;/h2&gt;

&lt;p&gt;A &lt;strong&gt;branch&lt;/strong&gt; is an independent line of development. You can create branches to work on features or fixes without touching the stable &lt;code&gt;main&lt;/code&gt; branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch &lt;span class="nt"&gt;-c&lt;/span&gt; feature/dark-mode     &lt;span class="c"&gt;# Create and switch to new branch&lt;/span&gt;
git switch main                     &lt;span class="c"&gt;# Switch back to main&lt;/span&gt;
git branch &lt;span class="nt"&gt;-d&lt;/span&gt; feature/dark-mode     &lt;span class="c"&gt;# Delete merged branch&lt;/span&gt;
git push origin feature/dark-mode   &lt;span class="c"&gt;# Push branch to remote&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A common branch naming convention:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Prefix&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;New feature&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feature/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feature/dark-mode&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bug fix&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fix/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fix/login-redirect&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Urgent fix&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hotfix/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hotfix/payment-crash&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Stash: The Pause Button for Unfinished Work
&lt;/h2&gt;

&lt;p&gt;You're halfway through a feature. Code is messy, not ready to commit. Then your team lead says: &lt;em&gt;"Can you quickly fix that bug on main?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;You can't switch branches with uncommitted changes. But you're not ready to commit either. The answer: &lt;strong&gt;stash it&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Analogy:&lt;/strong&gt; You're drawing a picture but need to use the table for something else. You put everything in a drawer. Later, you open the drawer and continue exactly where you left off.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash                           &lt;span class="c"&gt;# Save work temporarily&lt;/span&gt;
git switch fix/some-bug             &lt;span class="c"&gt;# Switch branches freely&lt;/span&gt;
&lt;span class="c"&gt;# ... fix the bug, commit, come back ...&lt;/span&gt;
git switch feature/dark-mode
git stash pop                       &lt;span class="c"&gt;# Restore your work&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adding a label makes it easier to manage multiple stashes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash push &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"WIP: dark mode palette"&lt;/span&gt;   &lt;span class="c"&gt;# Named stash&lt;/span&gt;
git stash list                               &lt;span class="c"&gt;# See all stashes&lt;/span&gt;
git stash pop                                &lt;span class="c"&gt;# Restore latest&lt;/span&gt;
git stash apply stash@&lt;span class="o"&gt;{&lt;/span&gt;1&lt;span class="o"&gt;}&lt;/span&gt;                    &lt;span class="c"&gt;# Restore specific (keep in list)&lt;/span&gt;
git stash drop stash@&lt;span class="o"&gt;{&lt;/span&gt;1&lt;span class="o"&gt;}&lt;/span&gt;                     &lt;span class="c"&gt;# Remove specific&lt;/span&gt;
git stash &lt;span class="nt"&gt;-u&lt;/span&gt;                                 &lt;span class="c"&gt;# Include untracked (new) files&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Worktree: No Stash Needed
&lt;/h2&gt;

&lt;p&gt;Stash works well for quick interruptions. But if the other task is longer — or you simply don't want to touch your current work at all — &lt;strong&gt;Git Worktree&lt;/strong&gt; is the cleaner solution.&lt;/p&gt;

&lt;p&gt;Worktree lets you check out a second branch in a &lt;strong&gt;separate folder&lt;/strong&gt;, without touching your current work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create a new folder with a different branch checked out&lt;/span&gt;
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; hotfix/login-bug ../my-project-hotfix origin/main

&lt;span class="c"&gt;# Work in that folder, commit, push&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project-hotfix
git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Fix login redirect"&lt;/span&gt;
git push origin hotfix/login-bug

&lt;span class="c"&gt;# Remove the worktree when done&lt;/span&gt;
git worktree remove ../my-project-hotfix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Both folders share the &lt;strong&gt;same &lt;code&gt;.git&lt;/code&gt; directory&lt;/strong&gt; — one repo, two windows into it. GUI tools like GitHub Desktop, GitKraken, and Fork all recognize it as one repo.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Stash&lt;/th&gt;
&lt;th&gt;Worktree&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Current work&lt;/td&gt;
&lt;td&gt;Saved and hidden&lt;/td&gt;
&lt;td&gt;Completely untouched&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multiple branches at once&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ideal for&lt;/td&gt;
&lt;td&gt;Quick interruptions&lt;/td&gt;
&lt;td&gt;Longer parallel work&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Merge &amp;amp; Pull Requests: Bringing It All Together
&lt;/h2&gt;

&lt;p&gt;When your feature is ready, you &lt;strong&gt;merge&lt;/strong&gt; it back into &lt;code&gt;main&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch main
git merge feature/dark-mode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On GitHub/GitLab, this is typically done through a &lt;strong&gt;Pull Request&lt;/strong&gt; (PR) — a formal process where:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You push your branch and open a PR&lt;/li&gt;
&lt;li&gt;Teammates review your code and leave feedback&lt;/li&gt;
&lt;li&gt;Once approved, it gets merged&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Merge Options
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;What happens&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Merge commit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All commits preserved + merge commit added&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Squash and merge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;All commits squashed into one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rebase and merge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Commits replayed on top of main, no merge commit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Handling Conflicts
&lt;/h3&gt;

&lt;p&gt;When two branches edit the same line, Git can't auto-merge. You'll see:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD
&lt;/span&gt;&lt;span class="p"&gt;const msg = "Hello!";
&lt;/span&gt;&lt;span class="gh"&gt;=======
&lt;/span&gt;&lt;span class="p"&gt;const msg = "Hi there!";
&lt;/span&gt;&lt;span class="gi"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; feature/dark-mode
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Manually resolve it, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &amp;lt;file&amp;gt;
git commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rebase: A Cleaner Alternative to Merge
&lt;/h3&gt;

&lt;p&gt;When you're the &lt;strong&gt;only one working on a branch&lt;/strong&gt;, rebase is a great way to keep your branch up to date with &lt;code&gt;main&lt;/code&gt; — without creating merge commits.&lt;/p&gt;

&lt;p&gt;Instead of merging &lt;code&gt;main&lt;/code&gt; into your branch (which adds noise), rebase &lt;em&gt;replays&lt;/em&gt; your commits on top of the latest &lt;code&gt;main&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin
git rebase origin/main

&lt;span class="c"&gt;# If conflicts arise during rebase:&lt;/span&gt;
git add &amp;lt;file&amp;gt;
git rebase &lt;span class="nt"&gt;--continue&lt;/span&gt;   &lt;span class="c"&gt;# move to next commit&lt;/span&gt;
git rebase &lt;span class="nt"&gt;--abort&lt;/span&gt;      &lt;span class="c"&gt;# cancel and go back&lt;/span&gt;

&lt;span class="c"&gt;# Force push after rebase (required — history was rewritten)&lt;/span&gt;
git push origin feature/dark-mode &lt;span class="nt"&gt;--force-with-lease&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Never rebase a branch other people are also working on.&lt;/strong&gt; Rebase rewrites history — it's only safe when you're the sole author of that branch.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situation&lt;/th&gt;
&lt;th&gt;Use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Solo feature branch, want clean history&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rebase&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Shared branch or already merged&lt;/td&gt;
&lt;td&gt;&lt;code&gt;merge&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Preparing a clean PR&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;rebase&lt;/code&gt; first, then open PR&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Code Reviews: The Quality Gate
&lt;/h2&gt;

&lt;p&gt;Before a PR is merged, someone reviews it. Good reviewers check for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logical correctness&lt;/li&gt;
&lt;li&gt;Readability and naming&lt;/li&gt;
&lt;li&gt;Test coverage&lt;/li&gt;
&lt;li&gt;Complexity (is it simpler than it needs to be?)&lt;/li&gt;
&lt;li&gt;Style guideline compliance&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Code reviews aren't just about catching mistakes — they're also how knowledge spreads through a team.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fork &amp;amp; Clone: Contributing Without Access
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Forking&lt;/strong&gt; copies someone else's repo into your GitHub account. &lt;strong&gt;Cloning&lt;/strong&gt; copies a repo to your local machine.&lt;/p&gt;

&lt;p&gt;The typical open-source contribution flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Fork on GitHub (click the Fork button)&lt;/span&gt;

&lt;span class="c"&gt;# 2. Clone your fork&lt;/span&gt;
git clone https://github.com/your-username/the-project.git

&lt;span class="c"&gt;# 3. Add original repo as upstream&lt;/span&gt;
git remote add upstream https://github.com/original-owner/the-project.git

&lt;span class="c"&gt;# 4. Create a branch, make changes, push&lt;/span&gt;
git switch &lt;span class="nt"&gt;-c&lt;/span&gt; fix/typo-readme
git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Fix typo in README"&lt;/span&gt;
git push origin fix/typo-readme

&lt;span class="c"&gt;# 5. Open a Pull Request on GitHub&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Keeping Your Fork Synced
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch upstream
git switch main
git merge upstream/main
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Git GUI Apps: You Don't Have to Type Everything
&lt;/h2&gt;

&lt;p&gt;Knowing the commands makes you a stronger developer — but you don't have to use the terminal every day. There's a whole ecosystem of GUI (Graphical User Interface) apps that let you commit, branch, merge, and stash by clicking buttons, with a visual map of your repo history.&lt;/p&gt;

&lt;p&gt;Here are the most popular ones:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;App&lt;/th&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Price&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub Desktop&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mac, Windows&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Beginners, GitHub users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;GitLens&lt;/strong&gt; (VS Code ext.)&lt;/td&gt;
&lt;td&gt;All OS&lt;/td&gt;
&lt;td&gt;Free / Paid&lt;/td&gt;
&lt;td&gt;Devs living in VS Code/Cursor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitKraken&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mac, Win, Linux&lt;/td&gt;
&lt;td&gt;Free (limited) / Paid&lt;/td&gt;
&lt;td&gt;Visual power users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fork&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mac, Windows&lt;/td&gt;
&lt;td&gt;Free trial / ~$50&lt;/td&gt;
&lt;td&gt;Speed + power balance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sourcetree&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mac, Windows&lt;/td&gt;
&lt;td&gt;Free&lt;/td&gt;
&lt;td&gt;Atlassian/Bitbucket users&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;GitHub Desktop&lt;/strong&gt; is the simplest — made by GitHub, focused on the essentials.&lt;br&gt;
&lt;strong&gt;GitLens&lt;/strong&gt; is a VS Code extension that adds inline blame, visual commit graphs, and stash management right inside your editor.&lt;br&gt;
&lt;strong&gt;GitKraken&lt;/strong&gt; has a stunning commit graph and drag-and-drop merging.&lt;br&gt;
&lt;strong&gt;Fork&lt;/strong&gt; hits a great balance of speed and power.&lt;br&gt;
&lt;strong&gt;Sourcetree&lt;/strong&gt; (by Atlassian) is free and feature-rich, especially if you use Bitbucket.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Even if you use a GUI app daily, knowing the underlying commands helps you debug problems and work on servers where no GUI exists. Think of GUI apps as a productivity layer on top of your Git knowledge — not a replacement for it.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;In Short&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Repository&lt;/td&gt;
&lt;td&gt;Warehouse for your project files + history&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit&lt;/td&gt;
&lt;td&gt;A saved snapshot with a message&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checkout&lt;/td&gt;
&lt;td&gt;Visit past commits temporarily&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reset&lt;/td&gt;
&lt;td&gt;Erase commit history (use carefully)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Revert&lt;/td&gt;
&lt;td&gt;Safely undo a commit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch&lt;/td&gt;
&lt;td&gt;Independent line of development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stash&lt;/td&gt;
&lt;td&gt;Temporarily save unfinished work&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worktree&lt;/td&gt;
&lt;td&gt;Work on two branches at once in separate folders&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Merge&lt;/td&gt;
&lt;td&gt;Combine branches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rebase&lt;/td&gt;
&lt;td&gt;Replay your commits on top of another branch (solo branches only)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pull Request&lt;/td&gt;
&lt;td&gt;Formal request to review and merge code&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fork&lt;/td&gt;
&lt;td&gt;Copy someone else's repo to your account&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clone&lt;/td&gt;
&lt;td&gt;Copy a repo to your local machine&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;Git takes practice, but these concepts cover 90% of what you'll use day-to-day. Start small, commit often, and don't be afraid of making branches.&lt;/p&gt;

&lt;p&gt;The more you use it, the more natural it feels.&lt;/p&gt;

&lt;p&gt;One commit at a time. 🚀&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published as a series (Git for Everyone) at: &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-1-what-is-git-repository-commit" rel="noopener noreferrer"&gt;What Is Git, Repository, and Commit&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-2-checkout-reset-revert" rel="noopener noreferrer"&gt;Traveling Through Time — Checkout, Reset, and Revert&lt;br&gt;
&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-3-branches-stash-workflow" rel="noopener noreferrer"&gt;Branches, Stash, and Git Workflow&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-4-merge-pull-request-code-review" rel="noopener noreferrer"&gt;Merge, Pull Requests, and Code Reviews&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-5-fork-clone-open-source" rel="noopener noreferrer"&gt;Fork, Clone, and Open Source Collaboration&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-6-git-gui-apps" rel="noopener noreferrer"&gt;Git GUI Apps — You Don't Have to Use the Terminal&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>beginners</category>
      <category>versioncontrol</category>
      <category>programming</category>
    </item>
    <item>
      <title>Git &amp; Kolaborasi: Panduan untuk Pemula (Lengkap dengan Analogi)</title>
      <dc:creator>Sanudin</dc:creator>
      <pubDate>Mon, 08 Jun 2026 00:36:09 +0000</pubDate>
      <link>https://dev.to/sanudin-dev/git-kolaborasi-panduan-untuk-pemula-lengkap-dengan-analogi-56ch</link>
      <guid>https://dev.to/sanudin-dev/git-kolaborasi-panduan-untuk-pemula-lengkap-dengan-analogi-56ch</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🌐 Baca artikel ini dalam Bahasa Inggris di &lt;a href="https://dev.to/sanudin-dev/git-collaboration-a-beginners-guide-with-real-analogies-4oh7"&gt;sini&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📝 Catatan tentang artikel ini&lt;/strong&gt;&lt;br&gt;
Artikel ini dibuat berdasarkan catatan belajar pribadi saya. Ide, perjalanan belajar, dan pemahamannya adalah milik saya — saya menggunakan AI untuk menyusun dan mengembangkannya menjadi artikel blog yang lebih muda dibaca.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Belajar Git itu tidak harus membingungkan. Di artikel ini, saya akan menjelaskan konsep-konsep penting dalam version control dan kolaborasi menggunakan bahasa yang sederhana — bahkan dengan analogi yang bisa dipahami anak kecil sekalipun.&lt;/p&gt;




&lt;h2&gt;
  
  
  Apa Itu Git?
&lt;/h2&gt;

&lt;p&gt;Git adalah &lt;strong&gt;version control system&lt;/strong&gt; — sistem yang merekam setiap perubahan yang kamu lakukan pada file-file proyekmu.&lt;/p&gt;

&lt;p&gt;Bayangkan Git seperti fitur &lt;em&gt;save point&lt;/em&gt; di video game. Setiap kali kamu menyimpan (commit), Git mengambil "foto" dari kondisi proyekmu saat itu. Kalau ada yang salah, kamu bisa kembali ke foto sebelumnya.&lt;/p&gt;




&lt;h2&gt;
  
  
  Repository: Gudang Proyekmu
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Repository&lt;/strong&gt; (atau "repo") adalah folder yang diawasi oleh Git. Ada dua jenisnya:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Local repository&lt;/strong&gt;: ada di komputermu sendiri. Ruang kerja pribadimu.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remote repository&lt;/strong&gt;: ada di server (GitHub, GitLab, Bitbucket). Salinan "resmi" yang bisa diakses seluruh tim.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Keduanya terhubung lewat Remote URL, sehingga kamu bisa mengirim perubahan ke remote (&lt;em&gt;push&lt;/em&gt;) atau mengambil perubahan terbaru dari sana (&lt;em&gt;pull&lt;/em&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git init                            &lt;span class="c"&gt;# Mulai memantau sebuah folder&lt;/span&gt;
git remote add origin &amp;lt;url&amp;gt;         &lt;span class="c"&gt;# Hubungkan ke remote repo&lt;/span&gt;
git push origin main                &lt;span class="c"&gt;# Kirim commit ke remote&lt;/span&gt;
git pull origin main                &lt;span class="c"&gt;# Ambil update terbaru dari remote&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Analogi:&lt;/strong&gt; Local repo adalah buku sketsamu di rumah. Remote repo adalah papan pengumuman kelas — semua orang bisa melihat dan mengaksesnya.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Commit: Save Point Proyekmu
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Commit&lt;/strong&gt; adalah snapshot dari kondisi proyekmu pada satu titik waktu. Setiap commit berisi:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pesan yang menjelaskan apa yang berubah&lt;/li&gt;
&lt;li&gt;ID unik (hash)&lt;/li&gt;
&lt;li&gt;Timestamp
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &lt;span class="nb"&gt;.&lt;/span&gt;                           &lt;span class="c"&gt;# Staging semua perubahan&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Tambah layout halaman utama"&lt;/span&gt;  &lt;span class="c"&gt;# Simpan snapshot&lt;/span&gt;
git log &lt;span class="nt"&gt;--oneline&lt;/span&gt;                   &lt;span class="c"&gt;# Lihat riwayat commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tulis pesan commit yang jelas dan bermakna. Dirimu di masa depan — dan rekan timmu — akan berterima kasih.&lt;/p&gt;




&lt;h2&gt;
  
  
  Checkout, Reset, Revert: Mesin Waktu Git
&lt;/h2&gt;

&lt;p&gt;Ketiga perintah ini berinteraksi dengan riwayat commit — tapi dengan cara yang sangat berbeda:&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;git checkout&lt;/code&gt; — Kunjungi Masa Lalu (Sementara)
&lt;/h3&gt;

&lt;p&gt;Seperti mesin waktu dengan tiket visitor. Kamu bisa melihat kondisi kode di commit lama tanpa mengubah apapun secara permanen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout &amp;lt;commit-hash&amp;gt;          &lt;span class="c"&gt;# Kunjungi commit lama&lt;/span&gt;
git checkout main                   &lt;span class="c"&gt;# Kembali ke sekarang&lt;/span&gt;
git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; branch-baru &amp;lt;&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;  &lt;span class="c"&gt;# Buat branch baru dari commit lama&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;git reset&lt;/code&gt; — Hapus Riwayat
&lt;/h3&gt;

&lt;p&gt;Kembali ke commit tertentu dan &lt;strong&gt;menghapus&lt;/strong&gt; semua yang terjadi setelahnya. Gunakan dengan hati-hati — terutama jika sudah di-push ke remote.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git reset &lt;span class="nt"&gt;--soft&lt;/span&gt; HEAD~1             &lt;span class="c"&gt;# Undo commit terakhir, perubahan tetap ada (staged)&lt;/span&gt;
git reset &lt;span class="nt"&gt;--hard&lt;/span&gt; HEAD~1             &lt;span class="c"&gt;# Undo commit terakhir, perubahan ikut terhapus&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;git revert&lt;/code&gt; — Undo yang Aman
&lt;/h3&gt;

&lt;p&gt;Membuat &lt;strong&gt;commit baru&lt;/strong&gt; yang membalikkan efek dari commit sebelumnya. Riwayat tetap utuh — pilihan paling aman saat bekerja di repo bersama.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git revert &amp;lt;commit-hash&amp;gt;            &lt;span class="c"&gt;# Undo sebuah commit dengan aman&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Panduan praktis:&lt;/strong&gt; Kalau sudah di-push, gunakan &lt;code&gt;revert&lt;/code&gt;. Kalau belum, &lt;code&gt;reset&lt;/code&gt; tidak masalah.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Branch: Jalur Paralel untuk Kode
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Branch&lt;/strong&gt; adalah jalur pengembangan yang terpisah. Kamu bisa membuat branch untuk mengerjakan fitur atau perbaikan bug tanpa menyentuh branch &lt;code&gt;main&lt;/code&gt; yang stabil.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch &lt;span class="nt"&gt;-c&lt;/span&gt; feature/dark-mode     &lt;span class="c"&gt;# Buat dan pindah ke branch baru&lt;/span&gt;
git switch main                     &lt;span class="c"&gt;# Kembali ke main&lt;/span&gt;
git branch &lt;span class="nt"&gt;-d&lt;/span&gt; feature/dark-mode     &lt;span class="c"&gt;# Hapus branch yang sudah di-merge&lt;/span&gt;
git push origin feature/dark-mode   &lt;span class="c"&gt;# Push branch ke remote&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Konvensi penamaan branch yang umum:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tipe&lt;/th&gt;
&lt;th&gt;Prefix&lt;/th&gt;
&lt;th&gt;Contoh&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Fitur baru&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feature/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;feature/dark-mode&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Perbaikan bug&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fix/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;fix/login-redirect&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hotfix mendesak&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hotfix/&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;hotfix/payment-crash&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Analogi:&lt;/strong&gt; Bayangkan sungai yang mengalir. Branch adalah anak sungai yang memisah diri untuk menjelajahi jalur lain — dan nantinya bergabung kembali ke sungai utama.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Stash: Tombol Pause untuk Pekerjaan yang Belum Selesai
&lt;/h2&gt;

&lt;p&gt;Kamu sedang di tengah-tengah mengerjakan sebuah fitur. Kode masih berantakan, belum siap untuk di-commit. Tiba-tiba team lead bilang: &lt;em&gt;"Bisa tolong perbaiki bug itu di branch main sekarang?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Kamu tidak bisa switch branch dengan perubahan yang belum di-commit. Tapi kamu juga belum siap commit. Jawabannya: &lt;strong&gt;simpan dulu dengan stash&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Analogi:&lt;/strong&gt; Kamu sedang menggambar tapi meja harus dipakai untuk hal lain. Kamu dengan rapi menyimpan gambar dan pensil ke dalam laci. Nanti kamu buka lacinya dan lanjut persis dari titik yang sama.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash                           &lt;span class="c"&gt;# Simpan pekerjaan sementara&lt;/span&gt;
git switch fix/some-bug             &lt;span class="c"&gt;# Bebas pindah branch&lt;/span&gt;
&lt;span class="c"&gt;# ... perbaiki bug, commit, balik lagi ...&lt;/span&gt;
git switch feature/dark-mode
git stash pop                       &lt;span class="c"&gt;# Kembalikan pekerjaanmu&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Menambahkan label membuat stash lebih mudah dikelola:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git stash push &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"WIP: palet dark mode"&lt;/span&gt;     &lt;span class="c"&gt;# Stash dengan nama&lt;/span&gt;
git stash list                               &lt;span class="c"&gt;# Lihat semua stash&lt;/span&gt;
git stash pop                                &lt;span class="c"&gt;# Kembalikan stash terbaru&lt;/span&gt;
git stash apply stash@&lt;span class="o"&gt;{&lt;/span&gt;1&lt;span class="o"&gt;}&lt;/span&gt;                    &lt;span class="c"&gt;# Kembalikan stash tertentu (tetap di list)&lt;/span&gt;
git stash drop stash@&lt;span class="o"&gt;{&lt;/span&gt;1&lt;span class="o"&gt;}&lt;/span&gt;                     &lt;span class="c"&gt;# Hapus stash tertentu&lt;/span&gt;
git stash &lt;span class="nt"&gt;-u&lt;/span&gt;                                 &lt;span class="c"&gt;# Sertakan file baru yang belum di-track&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Worktree: Tanpa Perlu Stash
&lt;/h2&gt;

&lt;p&gt;Stash cocok untuk interupsi singkat. Tapi kalau tugasnya lebih panjang — atau kamu tidak ingin menyentuh pekerjaan saat ini sama sekali — &lt;strong&gt;Git Worktree&lt;/strong&gt; adalah solusi yang lebih bersih.&lt;/p&gt;

&lt;p&gt;Worktree memungkinkan kamu checkout branch kedua di &lt;strong&gt;folder terpisah&lt;/strong&gt;, tanpa menyentuh pekerjaan yang sedang berjalan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Buat folder baru dengan branch yang berbeda&lt;/span&gt;
git worktree add &lt;span class="nt"&gt;-b&lt;/span&gt; hotfix/login-bug ../my-project-hotfix origin/main

&lt;span class="c"&gt;# Kerjakan di folder itu, commit, push&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ../my-project-hotfix
git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Fix login redirect"&lt;/span&gt;
git push origin hotfix/login-bug

&lt;span class="c"&gt;# Hapus worktree setelah selesai&lt;/span&gt;
git worktree remove ../my-project-hotfix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kedua folder berbagi &lt;strong&gt;satu &lt;code&gt;.git&lt;/code&gt; directory&lt;/strong&gt; yang sama — satu repo, dua jendela ke dalamnya. Tools seperti GitHub Desktop, GitKraken, dan Fork tetap mengenalinya sebagai satu repo.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Stash&lt;/th&gt;
&lt;th&gt;Worktree&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Pekerjaan saat ini&lt;/td&gt;
&lt;td&gt;Disimpan sementara&lt;/td&gt;
&lt;td&gt;Sama sekali tidak tersentuh&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Beberapa branch sekaligus&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cocok untuk&lt;/td&gt;
&lt;td&gt;Interupsi singkat&lt;/td&gt;
&lt;td&gt;Pekerjaan paralel yang lebih lama&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Merge &amp;amp; Pull Request: Menyatukan Pekerjaan
&lt;/h2&gt;

&lt;p&gt;Saat fiturmu selesai, kamu &lt;strong&gt;merge&lt;/strong&gt; branch-mu kembali ke &lt;code&gt;main&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git switch main
git merge feature/dark-mode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Di GitHub/GitLab, proses ini biasanya dilakukan lewat &lt;strong&gt;Pull Request&lt;/strong&gt; (PR):&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Push branch-mu dan buka PR&lt;/li&gt;
&lt;li&gt;Rekan tim me-review kode dan meninggalkan komentar&lt;/li&gt;
&lt;li&gt;Setelah disetujui, kode di-merge&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Tiga Opsi Merge
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metode&lt;/th&gt;
&lt;th&gt;Yang Terjadi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Merge commit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Semua commit dipertahankan + merge commit ditambahkan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Squash and merge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Semua commit digabung jadi satu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rebase and merge&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Commit diputar ulang di atas main, tanpa merge commit&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Menangani Conflict
&lt;/h3&gt;

&lt;p&gt;Ketika dua branch mengedit baris yang sama, Git tidak bisa merge otomatis. Kamu akan melihat:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD
&lt;/span&gt;&lt;span class="p"&gt;const msg = "Halo!";
&lt;/span&gt;&lt;span class="gh"&gt;=======
&lt;/span&gt;&lt;span class="p"&gt;const msg = "Hai semuanya!";
&lt;/span&gt;&lt;span class="gi"&gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; feature/dark-mode
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Selesaikan secara manual, lalu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git add &amp;lt;file&amp;gt;
git commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rebase: Alternatif yang Lebih Bersih dari Merge
&lt;/h3&gt;

&lt;p&gt;Ketika kamu &lt;strong&gt;satu-satunya yang mengerjakan sebuah branch&lt;/strong&gt;, rebase adalah cara yang bagus untuk menjaga branch-mu tetap update dengan &lt;code&gt;main&lt;/code&gt; — tanpa membuat merge commit yang mengotori riwayat.&lt;/p&gt;

&lt;p&gt;Alih-alih merge &lt;code&gt;main&lt;/code&gt; ke branch-mu, rebase &lt;em&gt;memutar ulang&lt;/em&gt; commit-commitmu di atas &lt;code&gt;main&lt;/code&gt; yang terbaru:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch origin
git rebase origin/main

&lt;span class="c"&gt;# Jika ada conflict saat rebase:&lt;/span&gt;
git add &amp;lt;file&amp;gt;
git rebase &lt;span class="nt"&gt;--continue&lt;/span&gt;   &lt;span class="c"&gt;# lanjut ke commit berikutnya&lt;/span&gt;
git rebase &lt;span class="nt"&gt;--abort&lt;/span&gt;      &lt;span class="c"&gt;# batalkan dan kembali ke sebelumnya&lt;/span&gt;

&lt;span class="c"&gt;# Force push setelah rebase (wajib — karena riwayat sudah ditulis ulang)&lt;/span&gt;
git push origin feature/dark-mode &lt;span class="nt"&gt;--force-with-lease&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Jangan pernah rebase branch yang juga dikerjakan orang lain.&lt;/strong&gt; Rebase menulis ulang riwayat — hanya aman jika kamu satu-satunya yang mengerjakan branch tersebut.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Situasi&lt;/th&gt;
&lt;th&gt;Gunakan&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Feature branch solo, ingin riwayat bersih&lt;/td&gt;
&lt;td&gt;&lt;code&gt;rebase&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch bersama atau sudah di-merge&lt;/td&gt;
&lt;td&gt;&lt;code&gt;merge&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Mempersiapkan PR yang bersih&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;rebase&lt;/code&gt; dulu, baru buka PR&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Code Review: Pintu Gerbang Kualitas
&lt;/h2&gt;

&lt;p&gt;Sebelum PR di-merge, seseorang akan me-review kodenya. Reviewer yang baik memeriksa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apakah logikanya benar?&lt;/li&gt;
&lt;li&gt;Apakah kode mudah dibaca dan penamaannya jelas?&lt;/li&gt;
&lt;li&gt;Apakah ada test yang cukup?&lt;/li&gt;
&lt;li&gt;Apakah kode lebih kompleks dari yang seharusnya?&lt;/li&gt;
&lt;li&gt;Apakah sesuai dengan style guideline tim?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Code review bukan sekadar mencari kesalahan — ini juga cara pengetahuan menyebar di seluruh tim. Jangan lupa juga memberikan pujian ketika kode sudah ditulis dengan baik.&lt;/p&gt;




&lt;h2&gt;
  
  
  Fork &amp;amp; Clone: Berkontribusi Tanpa Akses
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Forking&lt;/strong&gt; menyalin repo orang lain ke akun GitHub-mu. &lt;strong&gt;Cloning&lt;/strong&gt; menyalin repo ke komputer lokalmu.&lt;/p&gt;

&lt;p&gt;Alur kontribusi open source yang umum:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Fork di GitHub (klik tombol Fork)&lt;/span&gt;

&lt;span class="c"&gt;# 2. Clone fork-mu&lt;/span&gt;
git clone https://github.com/username-kamu/nama-proyek.git

&lt;span class="c"&gt;# 3. Tambahkan repo asli sebagai upstream&lt;/span&gt;
git remote add upstream https://github.com/pemilik-asli/nama-proyek.git

&lt;span class="c"&gt;# 4. Buat branch, buat perubahan, push&lt;/span&gt;
git switch &lt;span class="nt"&gt;-c&lt;/span&gt; fix/typo-readme
git add &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Perbaiki typo di README"&lt;/span&gt;
git push origin fix/typo-readme

&lt;span class="c"&gt;# 5. Buka Pull Request di GitHub&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Sinkronisasi Fork-mu
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git fetch upstream
git switch main
git merge upstream/main
git push origin main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Perbedaan Fork vs Clone:&lt;/strong&gt; Fork menyalin ke akun GitHub-mu (remote). Clone menyalin ke komputermu (lokal). Keduanya tidak mempengaruhi repo asli.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Tips untuk Mulai Berkontribusi
&lt;/h2&gt;

&lt;p&gt;Kalau kamu baru ingin terjun ke open source:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mulai dari yang kecil&lt;/strong&gt; — perbaiki typo di dokumentasi, tambahkan komentar, perbaiki README. Jangan langsung menyerang bug paling kompleks.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pelajari ekosistem proyek&lt;/strong&gt; — baca &lt;code&gt;README.md&lt;/code&gt;, &lt;code&gt;CONTRIBUTING.md&lt;/code&gt;, dan riwayat commit untuk memahami konvensi yang digunakan.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ikuti konvensi yang ada&lt;/strong&gt; — cara menulis commit, penamaan branch, format PR description.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Aplikasi Git GUI: Tidak Harus Selalu Pakai Terminal
&lt;/h2&gt;

&lt;p&gt;Mengetahui perintahnya membuatmu jadi developer yang lebih kuat — tapi kamu tidak harus mengetik di terminal setiap hari. Ada banyak &lt;strong&gt;aplikasi GUI (Graphical User Interface)&lt;/strong&gt; yang memungkinkan kamu commit, branch, merge, dan stash hanya dengan klik, plus visualisasi riwayat repo yang mudah dipahami.&lt;/p&gt;

&lt;p&gt;Berikut yang paling populer:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aplikasi&lt;/th&gt;
&lt;th&gt;Platform&lt;/th&gt;
&lt;th&gt;Harga&lt;/th&gt;
&lt;th&gt;Cocok Untuk&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitHub Desktop&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mac, Windows&lt;/td&gt;
&lt;td&gt;Gratis&lt;/td&gt;
&lt;td&gt;Pemula, pengguna GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;GitLens&lt;/strong&gt; (ext. VS Code)&lt;/td&gt;
&lt;td&gt;Semua OS&lt;/td&gt;
&lt;td&gt;Gratis / Berbayar&lt;/td&gt;
&lt;td&gt;Developer yang sehari-hari di VS Code/Cursor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;GitKraken&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mac, Win, Linux&lt;/td&gt;
&lt;td&gt;Gratis (terbatas) / Berbayar&lt;/td&gt;
&lt;td&gt;Power user visual&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Fork&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mac, Windows&lt;/td&gt;
&lt;td&gt;Gratis trial / ~$50&lt;/td&gt;
&lt;td&gt;Keseimbangan kecepatan &amp;amp; fitur&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sourcetree&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mac, Windows&lt;/td&gt;
&lt;td&gt;Gratis&lt;/td&gt;
&lt;td&gt;Pengguna Atlassian/Bitbucket&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;GitHub Desktop&lt;/strong&gt; adalah yang paling sederhana — dibuat oleh GitHub, fokus pada hal-hal esensial.&lt;br&gt;
&lt;strong&gt;GitLens&lt;/strong&gt; adalah ekstensi VS Code yang menambahkan inline blame, visual commit graph, dan manajemen stash langsung di dalam editor-mu.&lt;br&gt;
&lt;strong&gt;GitKraken&lt;/strong&gt; punya tampilan commit graph yang keren dan fitur drag-and-drop untuk merge.&lt;br&gt;
&lt;strong&gt;Fork&lt;/strong&gt; menawarkan keseimbangan yang baik antara kecepatan dan fitur.&lt;br&gt;
&lt;strong&gt;Sourcetree&lt;/strong&gt; (buatan Atlassian) gratis dan kaya fitur, terutama kalau kamu pakai Bitbucket.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Meskipun pakai aplikasi GUI sehari-hari, memahami perintah dasarnya tetap penting — untuk debugging dan bekerja di server yang tidak punya GUI. Anggap aplikasi GUI sebagai lapisan produktivitas di atas pengetahuan Git-mu, bukan penggantinya.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Ringkasan
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Konsep&lt;/th&gt;
&lt;th&gt;Singkatnya&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Repository&lt;/td&gt;
&lt;td&gt;Gudang untuk file dan riwayat proyekmu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commit&lt;/td&gt;
&lt;td&gt;Snapshot tersimpan dengan pesan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Checkout&lt;/td&gt;
&lt;td&gt;Kunjungi commit lama sementara&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Reset&lt;/td&gt;
&lt;td&gt;Hapus riwayat commit (hati-hati)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Revert&lt;/td&gt;
&lt;td&gt;Undo commit dengan aman&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Branch&lt;/td&gt;
&lt;td&gt;Jalur pengembangan terpisah&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stash&lt;/td&gt;
&lt;td&gt;Simpan sementara pekerjaan yang belum selesai&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Worktree&lt;/td&gt;
&lt;td&gt;Kerjakan dua branch sekaligus di folder berbeda&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Merge&lt;/td&gt;
&lt;td&gt;Gabungkan dua branch&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rebase&lt;/td&gt;
&lt;td&gt;Putar ulang commit-mu di atas branch lain (khusus branch solo)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pull Request&lt;/td&gt;
&lt;td&gt;Permintaan formal untuk review dan merge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fork&lt;/td&gt;
&lt;td&gt;Salin repo orang lain ke akunmu&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Clone&lt;/td&gt;
&lt;td&gt;Salin repo ke komputer lokalmu&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;Git butuh waktu untuk terasa natural — tapi konsep-konsep di atas sudah mencakup 90% dari yang akan kamu pakai sehari-hari.&lt;/p&gt;

&lt;p&gt;Mulai dari yang kecil, commit sesering mungkin, dan jangan takut membuat branch baru.&lt;/p&gt;

&lt;p&gt;Satu commit pada satu waktu. 🚀&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published as a series (Git for Everyone) at: &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-1-what-is-git-repository-commit" rel="noopener noreferrer"&gt;What Is Git, Repository, and Commit&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-2-checkout-reset-revert" rel="noopener noreferrer"&gt;Traveling Through Time — Checkout, Reset, and Revert&lt;br&gt;
&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-3-branches-stash-workflow" rel="noopener noreferrer"&gt;Branches, Stash, and Git Workflow&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-4-merge-pull-request-code-review" rel="noopener noreferrer"&gt;Merge, Pull Requests, and Code Reviews&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-5-fork-clone-open-source" rel="noopener noreferrer"&gt;Fork, Clone, and Open Source Collaboration&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/git-for-everyone__part-6-git-gui-apps" rel="noopener noreferrer"&gt;Git GUI Apps — You Don't Have to Use the Terminal&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>git</category>
      <category>beginners</category>
      <category>versioncontrol</category>
      <category>programming</category>
    </item>
    <item>
      <title>From OOP to SOLID: Everything You Need to Know in One Article</title>
      <dc:creator>Sanudin</dc:creator>
      <pubDate>Sun, 24 May 2026 16:52:32 +0000</pubDate>
      <link>https://dev.to/sanudin-dev/from-oop-to-solid-everything-you-need-to-know-in-one-article-44co</link>
      <guid>https://dev.to/sanudin-dev/from-oop-to-solid-everything-you-need-to-know-in-one-article-44co</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🌐 Read this post in Bahasa Indonesia &lt;a href="https://dev.to/sanudin-dev/dari-oop-ke-solid-semua-yang-perlu-kamu-tahu-dalam-satu-artikel-1b6o"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📝 A note on this article&lt;/strong&gt;&lt;br&gt;
This post is based on my personal study notes. The ideas, learning journey, and understanding are mine — I used AI to help structure and expand them into a proper blog format form.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Good code doesn't happen by accident. Behind every codebase that's a pleasure to work with, there's a set of ideas guiding how things are structured and connected.&lt;/p&gt;

&lt;p&gt;This article covers that full journey — from what OOP is, how objects relate, what bad design looks like, and finally: the five SOLID principles that tie it all together.&lt;/p&gt;

&lt;p&gt;Let's go.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdx0eigrfmq8wyqzc70l0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdx0eigrfmq8wyqzc70l0.png" alt="blueprint with robot sketches" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 1: What Is OOP?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Object Oriented Programming (OOP)&lt;/strong&gt; is a way of writing code that mirrors the real world. Instead of one long list of instructions, you group related data and behavior into &lt;em&gt;objects&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤖 Think of a robot toy. It has &lt;strong&gt;properties&lt;/strong&gt; (color, height, battery) and &lt;strong&gt;behaviors&lt;/strong&gt; (walk, talk, wave). In OOP, that robot is an object — and the blueprint used to build it is called a &lt;strong&gt;class&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Two key terms:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Class&lt;/strong&gt; — the blueprint (template)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object&lt;/strong&gt; — a real instance built from the blueprint&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  The Four Pillars
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pillar&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inheritance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A child class inherits properties and behaviors from a parent class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Encapsulation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Internal data is hidden — only controlled access is allowed from outside&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Abstraction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Complex internals are hidden; only what's needed is exposed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Polymorphism&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;The same action can behave differently depending on the object&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqoftx9p60uad20eabucb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqoftx9p60uad20eabucb.png" alt="robots connected by lines showing relationships" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 2: How Objects Relate
&lt;/h2&gt;

&lt;p&gt;Objects don't exist in isolation. They connect, collaborate, and depend on each other — and the &lt;em&gt;type&lt;/em&gt; of relationship matters.&lt;/p&gt;

&lt;h3&gt;
  
  
  Association
&lt;/h3&gt;

&lt;p&gt;Two objects know about each other and can interact. Comes in three cardinalities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-to-one&lt;/strong&gt; — one passport per person&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-to-many&lt;/strong&gt; — one teacher, many students&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Many-to-many&lt;/strong&gt; — many students, many courses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Inside association, when one object "owns" another, the relationship is either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Aggregation&lt;/strong&gt; (loose) — the child survives without the parent. A backpack contains books, but the books still exist if you throw the backpack away.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composition&lt;/strong&gt; (tight) — the child cannot exist without the parent. A house has rooms; demolish the house, the rooms cease to exist.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dependency
&lt;/h3&gt;

&lt;p&gt;A temporary, usage-based relationship. One class uses another inside a method but doesn't hold onto it permanently. Weaker than association.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generalization &amp;amp; Realization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generalization&lt;/strong&gt; — pulling shared traits from multiple classes into one superclass (inheritance)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Realization&lt;/strong&gt; — a class implementing an interface, promising to fulfill a defined contract&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3grr9oexl2t6unn34oor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3grr9oexl2t6unn34oor.png" alt="tangled cables or cracked structure" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 3: What Bad Design Looks Like
&lt;/h2&gt;

&lt;p&gt;Before learning the rules, it helps to understand what you're guarding against. Robert C. Martin identified three symptoms of bad design:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🪨 Rigidity&lt;/strong&gt; — the system is hard to change. Touch one thing, and a cascade of other things need updating. Developers become afraid to make changes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🍪 Fragility&lt;/strong&gt; — the system breaks in unexpected places when you make a change. You fix a bug in the payment module, and somehow the email notifications stop working.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🏗️ Immobility&lt;/strong&gt; — useful components can't be reused. They're so entangled with their surroundings that extracting them would take longer than rewriting from scratch.&lt;/p&gt;

&lt;p&gt;All three share the same root cause: &lt;strong&gt;poor management of dependencies&lt;/strong&gt; between components.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8yvza2t207x7gsxizwu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8yvza2t207x7gsxizwu.png" alt="five geometric shapes in a clean grid" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Part 4: SOLID
&lt;/h2&gt;

&lt;p&gt;SOLID is a set of five principles that directly address the problems above. Each one targets a specific failure mode.&lt;/p&gt;




&lt;h3&gt;
  
  
  S — Single Responsibility Principle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"A module should be responsible to one, and only one, actor."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Every class should have exactly &lt;strong&gt;one reason to change&lt;/strong&gt; — it serves one actor (one group of stakeholders).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👨‍🍳 A restaurant worker who is simultaneously the chef, cashier, security guard, and delivery driver is a disaster waiting to happen. One change in one role disrupts all the others.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Split your classes. One responsibility each.&lt;/p&gt;




&lt;h3&gt;
  
  
  O — Open/Closed Principle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"A software artifact should be open for extension but closed for modification."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Add new behavior by &lt;strong&gt;extending&lt;/strong&gt; — not by editing existing, working code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔌 A power strip lets you plug in new devices without rewiring the strip itself. That's OCP in action.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When requirements change, slot in new code alongside the old — don't rewrite what's already working.&lt;/p&gt;




&lt;h3&gt;
  
  
  L — Liskov Substitution Principle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"If S is a subtype of T, objects of type T may be replaced with objects of type S without altering program correctness."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A subclass must be &lt;strong&gt;fully substitutable&lt;/strong&gt; for its parent class. Every promise the parent makes, the child must keep.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤖 If the parent robot can cook, the child robot must be able to cook too — not throw an error or silently do nothing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If your subclass has empty methods, stub implementations, or "not supported" throws — that's a Liskov violation.&lt;/p&gt;




&lt;h3&gt;
  
  
  I — Interface Segregation Principle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Clients should not be forced to depend upon interfaces that they do not use."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Don't create fat interfaces that force classes to implement methods they don't need. &lt;strong&gt;Split interfaces&lt;/strong&gt; into smaller, focused ones.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🍴 Don't give every restaurant customer a steak knife, soup spoon, chopsticks, and a fondue skewer when they only ordered soup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Smaller interfaces = narrower dependencies = changes stay localized.&lt;/p&gt;




&lt;h3&gt;
  
  
  D — Dependency Inversion Principle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"High-level modules should not depend on low-level modules. Both should depend on abstractions."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Your business logic should not be hardwired to specific implementations. It should talk to &lt;strong&gt;interfaces&lt;/strong&gt; — and the low-level details implement those interfaces.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤖 Don't solder a spatula into the robot's arm. Give the arm a standard connector, and let tools be swapped in and out.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is what makes infrastructure (databases, APIs, file systems) swappable without touching business logic.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Reference: SOLID at a Glance
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Principle&lt;/th&gt;
&lt;th&gt;Problem it solves&lt;/th&gt;
&lt;th&gt;Key question to ask&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SRP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Classes doing too much&lt;/td&gt;
&lt;td&gt;"Does this class serve more than one group of stakeholders?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Editing old code to add features&lt;/td&gt;
&lt;td&gt;"Can I add this as an extension instead of a modification?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LSP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Broken inheritance hierarchies&lt;/td&gt;
&lt;td&gt;"Can I swap the child for the parent without anything breaking?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ISP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Fat interfaces with unused methods&lt;/td&gt;
&lt;td&gt;"Is this class forced to implement something it doesn't need?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DIP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Business logic locked to infrastructure&lt;/td&gt;
&lt;td&gt;"Does my high-level code depend on a concrete class it shouldn't?"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Where to Start
&lt;/h2&gt;

&lt;p&gt;If you're applying these for the first time:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Start with SRP&lt;/strong&gt; — find your "doing too much" classes and split them&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check inheritance for LSP violations&lt;/strong&gt; — empty methods are the warning sign&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Introduce interfaces at infrastructure boundaries&lt;/strong&gt; — that's DIP in practice&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These principles aren't a checklist. They're questions to ask every time you sit down to write code.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published as a series at: &lt;a href="https://sanudin.dev/blog/oop-solid__part-1-what-is-oop" rel="noopener noreferrer"&gt;Part 1: What is OOP?&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/oop-solid__part-2-how-objects-relate" rel="noopener noreferrer"&gt;Part 2: When Objects Meet&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/oop-solid__part-3-why-bad-design-hurts" rel="noopener noreferrer"&gt;Part 3: Why Bad Design Hurts&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/oop-solid__part-4-solid" rel="noopener noreferrer"&gt;Part 4: SOLID&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>oop</category>
      <category>solid</category>
    </item>
    <item>
      <title>Dari OOP ke SOLID: Semua yang Perlu Kamu Tahu dalam Satu Artikel</title>
      <dc:creator>Sanudin</dc:creator>
      <pubDate>Sun, 24 May 2026 16:50:29 +0000</pubDate>
      <link>https://dev.to/sanudin-dev/dari-oop-ke-solid-semua-yang-perlu-kamu-tahu-dalam-satu-artikel-1b6o</link>
      <guid>https://dev.to/sanudin-dev/dari-oop-ke-solid-semua-yang-perlu-kamu-tahu-dalam-satu-artikel-1b6o</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;🌐 Baca artikel ini dalam Bahasa Inggris di &lt;a href="https://dev.to/sanudin-dev/from-oop-to-solid-everything-you-need-to-know-in-one-article-44co"&gt;sini&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;📝 Catatan tentang artikel ini&lt;/strong&gt;&lt;br&gt;
Artikel ini dibuat berdasarkan catatan belajar pribadi saya. Ide, perjalanan belajar, dan pemahamannya adalah milik saya — saya menggunakan AI untuk menyusun dan mengembangkannya menjadi artikel blog yang lebih muda dibaca.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;p&gt;Kode yang enak dibaca dan mudah diubah bukan kebetulan. Di balik setiap codebase yang menyenangkan untuk dikerjakan, ada sekumpulan ide yang memandu bagaimana semuanya disusun dan dihubungkan.&lt;/p&gt;

&lt;p&gt;Artikel ini membahas perjalanan lengkap itu — mulai dari apa itu OOP, bagaimana objek saling berhubungan, seperti apa desain yang buruk, hingga akhirnya: lima prinsip SOLID yang menyatukan semuanya.&lt;/p&gt;

&lt;p&gt;Yuk mulai.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdx0eigrfmq8wyqzc70l0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdx0eigrfmq8wyqzc70l0.png" alt="blueprint with robot sketches" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bagian 1: Apa Itu OOP?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Object Oriented Programming (OOP)&lt;/strong&gt; adalah cara menulis kode yang mencerminkan dunia nyata. Alih-alih satu daftar panjang instruksi, kamu mengelompokkan data dan perilaku yang saling berkaitan ke dalam &lt;em&gt;objek&lt;/em&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤖 Bayangkan mainan robot. Robot punya &lt;strong&gt;properti&lt;/strong&gt; (warna, tinggi, baterai) dan &lt;strong&gt;perilaku&lt;/strong&gt; (berjalan, berbicara, melambaikan tangan). Dalam OOP, robot itu adalah objek — dan cetak biru yang digunakan untuk membuatnya disebut &lt;strong&gt;class&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Dua istilah kunci:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Class&lt;/strong&gt; — cetak biru (template)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object&lt;/strong&gt; — wujud nyata yang dibuat dari cetak biru tersebut&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Empat Pilar OOP
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Pilar&lt;/th&gt;
&lt;th&gt;Fungsinya&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Inheritance&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Class anak mewarisi properti dan perilaku dari class induk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Encapsulation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Data internal disembunyikan — akses dari luar hanya melalui jalur yang ditentukan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Abstraction&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Kerumitan internal disembunyikan; hanya yang perlu digunakan saja yang ditampilkan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Polymorphism&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Aksi yang sama bisa berperilaku berbeda tergantung pada objeknya&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqoftx9p60uad20eabucb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqoftx9p60uad20eabucb.png" alt="robots connected by lines showing relationships" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bagian 2: Bagaimana Objek Saling Berhubungan
&lt;/h2&gt;

&lt;p&gt;Objek tidak hidup sendiri-sendiri. Mereka terhubung, bekerja sama, dan saling bergantung — dan &lt;em&gt;jenis&lt;/em&gt; hubungannya penting.&lt;/p&gt;

&lt;h3&gt;
  
  
  Asosiasi
&lt;/h3&gt;

&lt;p&gt;Dua objek saling mengenal dan bisa berinteraksi. Ada tiga jenis kardinalitas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;One-to-one&lt;/strong&gt; — satu orang satu paspor&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-to-many&lt;/strong&gt; — satu guru, banyak murid&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Many-to-many&lt;/strong&gt; — banyak murid, banyak mata pelajaran&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Dalam asosiasi, ketika satu objek "memiliki" objek lain, hubungannya bisa berupa:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Aggregation&lt;/strong&gt; (longgar) — objek anak bisa hidup tanpa induknya. Tas ransel berisi buku, tapi bukunya tetap ada meski tasnya dibuang.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Composition&lt;/strong&gt; (erat) — objek anak tidak bisa eksis tanpa induknya. Rumah punya kamar; hancurkan rumahnya, kamarnya ikut lenyap.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Dependency
&lt;/h3&gt;

&lt;p&gt;Hubungan sementara berbasis pemakaian. Satu class memakai class lain di dalam sebuah method, tapi tidak menyimpannya secara permanen. Lebih lemah dari asosiasi.&lt;/p&gt;

&lt;h3&gt;
  
  
  Generalization &amp;amp; Realization
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Generalization&lt;/strong&gt; — mengangkat sifat-sifat yang sama dari beberapa class ke satu superclass (pewarisan)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Realization&lt;/strong&gt; — sebuah class mengimplementasikan interface, berjanji untuk memenuhi kontrak yang sudah didefinisikan&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3grr9oexl2t6unn34oor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3grr9oexl2t6unn34oor.png" alt="tangled cables or cracked structure" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bagian 3: Seperti Apa Desain yang Buruk?
&lt;/h2&gt;

&lt;p&gt;Sebelum belajar aturannya, penting untuk memahami apa yang sedang kita hindari. Robert C. Martin mengidentifikasi tiga gejala desain yang buruk:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🪨 Rigidity (Kekakuan)&lt;/strong&gt; — sistem susah diubah. Sentuh satu hal, dan banyak hal lain ikut perlu diperbarui. Developer jadi takut untuk melakukan perubahan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🍪 Fragility (Kerapuhan)&lt;/strong&gt; — sistem rusak di tempat yang tidak terduga saat kamu melakukan perubahan. Kamu memperbaiki bug di modul pembayaran, tiba-tiba notifikasi email berhenti berfungsi.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🏗️ Immobility (Ketidakmampuan Dipindahkan)&lt;/strong&gt; — komponen yang berguna tidak bisa dipakai ulang. Mereka terlalu kusut dengan sekitarnya sehingga mencabutnya butuh lebih lama dari menulis ulang dari awal.&lt;/p&gt;

&lt;p&gt;Ketiganya punya akar penyebab yang sama: &lt;strong&gt;pengelolaan dependensi antar komponen yang buruk&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8yvza2t207x7gsxizwu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr8yvza2t207x7gsxizwu.png" alt="five geometric shapes in a clean grid" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bagian 4: SOLID
&lt;/h2&gt;

&lt;p&gt;SOLID adalah lima prinsip yang secara langsung mengatasi masalah di atas. Masing-masing menargetkan kegagalan desain yang spesifik.&lt;/p&gt;




&lt;h3&gt;
  
  
  S — Single Responsibility Principle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Sebuah modul harus bertanggung jawab pada satu, dan hanya satu, aktor."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Setiap class harus punya tepat &lt;strong&gt;satu alasan untuk berubah&lt;/strong&gt; — ia melayani satu aktor (satu kelompok stakeholder).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;👨‍🍳 Seorang pekerja restoran yang sekaligus menjadi koki, kasir, satpam, dan pengantar makanan adalah bencana yang menunggu terjadi. Perubahan di satu peran mengganggu semua peran lainnya.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Pisahkan class-mu. Satu tanggung jawab per class.&lt;/p&gt;




&lt;h3&gt;
  
  
  O — Open/Closed Principle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Artefak perangkat lunak harus terbuka untuk ditambahkan, tapi tertutup untuk dimodifikasi."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Tambahkan perilaku baru dengan cara &lt;strong&gt;memperluas&lt;/strong&gt; — bukan mengedit kode lama yang sudah berjalan.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🔌 Stop kontak memungkinkan kamu mencolokkan perangkat baru tanpa perlu membongkar kabelnya. Itulah OCP dalam praktik.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ketika kebutuhan berubah, tambahkan kode baru di samping yang lama — jangan tulis ulang yang sudah berjalan.&lt;/p&gt;




&lt;h3&gt;
  
  
  L — Liskov Substitution Principle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Jika S adalah subtipe dari T, objek bertipe T bisa digantikan dengan objek bertipe S tanpa mengubah kebenaran program."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Sebuah subclass harus &lt;strong&gt;sepenuhnya bisa menggantikan&lt;/strong&gt; class induknya. Setiap janji yang dibuat induk, harus dipenuhi oleh anak.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤖 Kalau robot induk bisa memasak, robot anak juga harus bisa memasak — bukan melempar error atau diam saja tanpa melakukan apa-apa.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Kalau subclass-mu punya method kosong, implementasi stub, atau melempar "not supported" — itu pelanggaran Liskov.&lt;/p&gt;




&lt;h3&gt;
  
  
  I — Interface Segregation Principle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Client tidak boleh dipaksa bergantung pada interface yang tidak mereka gunakan."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Jangan buat interface besar yang memaksa class mengimplementasikan method yang tidak mereka butuhkan. &lt;strong&gt;Pecah interface&lt;/strong&gt; menjadi bagian-bagian kecil yang lebih fokus.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🍴 Jangan berikan setiap pelanggan restoran pisau steak, sendok sup, sumpit, dan tusuk fondue ketika mereka hanya memesan sup.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Interface yang lebih kecil = dependensi yang lebih sempit = perubahan tetap terlokalisir.&lt;/p&gt;




&lt;h3&gt;
  
  
  D — Dependency Inversion Principle
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Modul tingkat tinggi tidak boleh bergantung pada modul tingkat rendah. Keduanya harus bergantung pada abstraksi."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Logika bisnis tidak boleh terkait langsung dengan implementasi spesifik. Ia harus bicara dengan &lt;strong&gt;interface&lt;/strong&gt; — dan detail tingkat rendah yang mengimplementasikan interface tersebut.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🤖 Jangan solder spatula ke tangan robot. Beri tangannya konektor standar, dan biarkan alat-alatnya bisa diganti-ganti.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Inilah yang membuat infrastruktur (database, API, file system) bisa diganti tanpa menyentuh logika bisnis.&lt;/p&gt;




&lt;h2&gt;
  
  
  Ringkasan Cepat: SOLID Sekilas
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Prinsip&lt;/th&gt;
&lt;th&gt;Masalah yang diatasi&lt;/th&gt;
&lt;th&gt;Pertanyaan kuncinya&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SRP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Class mengerjakan terlalu banyak hal&lt;/td&gt;
&lt;td&gt;"Apakah class ini melayani lebih dari satu kelompok stakeholder?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OCP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Mengedit kode lama untuk menambah fitur&lt;/td&gt;
&lt;td&gt;"Bisakah ini ditambahkan sebagai ekstensi, bukan modifikasi?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;LSP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Hirarki pewarisan yang rusak&lt;/td&gt;
&lt;td&gt;"Bisakah anak menggantikan induk tanpa ada yang rusak?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ISP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Interface gemuk dengan method yang tidak dipakai&lt;/td&gt;
&lt;td&gt;"Apakah class ini dipaksa mengimplementasikan sesuatu yang tidak dibutuhkan?"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;DIP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Logika bisnis terikat ke infrastruktur&lt;/td&gt;
&lt;td&gt;"Apakah kode tingkat tinggi bergantung pada class konkret yang seharusnya tidak?"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Mulai dari Mana?
&lt;/h2&gt;

&lt;p&gt;Kalau kamu baru pertama kali menerapkan ini:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Mulai dengan SRP&lt;/strong&gt; — cari class yang "mengerjakan terlalu banyak" dan pecah&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Periksa pewarisan untuk pelanggaran LSP&lt;/strong&gt; — method kosong adalah tanda peringatannya&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tambahkan interface di batas infrastruktur&lt;/strong&gt; — itulah DIP dalam praktik&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Prinsip-prinsip ini bukan checklist. Mereka adalah pertanyaan yang perlu kamu ajukan setiap kali duduk untuk menulis kode.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Originally published as a series at: &lt;a href="https://sanudin.dev/blog/oop-solid__part-1-what-is-oop" rel="noopener noreferrer"&gt;Part 1: What is OOP?&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/oop-solid__part-2-how-objects-relate" rel="noopener noreferrer"&gt;Part 2: When Objects Meet&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/oop-solid__part-3-why-bad-design-hurts" rel="noopener noreferrer"&gt;Part 3: Why Bad Design Hurts&lt;/a&gt; | &lt;a href="https://sanudin.dev/blog/oop-solid__part-4-solid" rel="noopener noreferrer"&gt;Part 4: SOLID&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>programming</category>
      <category>oop</category>
      <category>solid</category>
    </item>
  </channel>
</rss>
