Setiap pengembang pasti punya folder itu. Folder bernama utils atau helpers yang Anda salin dari satu repo ke repo lainnya. Anda menempelkannya, menghabiskan dua puluh menit untuk menghapus referensi ke skema database lama, mencabut pemeriksaan autentikasi yang tidak relevan, dan mengubah nama variabel agar linter baru Anda berhenti memberikan peringatan. Saya dulu melakukan ini dengan sistem penemaan yang saya bangun, Dynamic Theme Kit. Awalnya ini adalah sebuah fitur di dalam satu aplikasi, dan selama berbulan-bulan, saya memperlakukannya seperti alat portabel. Saya salah. Menyalin kode bukanlah penggunaan kembali (reuse). Itu adalah duplikasi dengan langkah tambahan.
Jebakan Pola Pikir Proyek Tunggal
Saat Anda membangun sebuah fitur di dalam sebuah proyek, Anda membuat ratusan asumsi yang tidak terlihat. Palet warna mungkin mengasumsikan pengaturan CSS-in-JS tertentu. Skala jarak (spacing scale) mungkin merujuk pada token desain dari panduan merek perusahaan Anda. Peralihan antara mode terang dan gelap mungkin memanggil endpoint preferensi pengguna yang unik bagi backend aplikasi tersebut. Dependensi ini terasa tidak berbahaya karena di dalam proyek tersebut, mereka memang tidak berbahaya. Mereka memang seharusnya ada di sana.
Masalah dimulai saat Anda mencoba mengangkat kode tersebut keluar. Anda menemukan bahwa komponen yang "dapat digunakan kembali" tersebut sebenarnya adalah jaring-jaring string tersembunyi yang menghubungkannya ke satu basis kode itu. Saya mempelajari hal ini dengan DTK. DTK menghasilkan variabel tema, ya. Namun, ia juga mengharapkan struktur folder tertentu. Ia mengimpor definisi tipe (type definition) dari suatu tempat yang dalam di direktori tipe aplikasi aslinya. Ia mengasumsikan keberadaan objek konfigurasi global yang hanya ada di satu repositori tersebut. Saya tidak pernah menyadarinya karena di dalam proyek tersebut, semuanya selalu tersedia.
Mengubah DTK menjadi paket mandiri (standalone package) berarti melakukan operasi bedah, bukan ekspansi. Saya tidak butuh lebih banyak fitur. Saya butuh lebih sedikit koneksi.
Mengekstrak Dynamic Theme Kit
Pekerjaan tersulit adalah duduk bersama basis kode (codebase) dan bertanya, untuk setiap fungsi dan setiap ekspor: apakah ini melayani logika tema, atau melayani proyeknya? Saya mencopot preset gaya (styling presets). Saya menghapus asumsi bahwa konsumennya harus berupa aplikasi React. Saya menghapus seluruh palet warna default. Proyek aslinya memiliki estetika korporat bernuansa navy-and-slate yang tertanam dalam pengaturan default. Itu harus dibuang. Sebuah paket tidak boleh menyertakan warna merek Anda.
Kit baru ini hanya akan melakukan satu hal. Ia mengambil sebuah objek konfigurasi—beberapa nilai warna, beberapa angka jarak, beberapa skala tipografi—dan ia menghasilkan properti CSS kustom. Itu saja. Ia tidak menerapkannya. Ia tidak memutuskan di mana properti tersebut diletakkan di DOM Anda. Ia tidak peduli apakah Anda menggunakan Tailwind, Styled Components, atau HTML biasa. Ia memberikan variabel kepada aplikasi Anda, dan proyek Anda yang memilih cara menggunakannya.
Batasan itu awalnya terasa mengekang. Ternyata, itu justru membebaskan.
Apa yang Rusak Saat Anda Benar-benar Mencoba Menggunakannya Kembali
Sebelum saya mempublikasikan apa pun, saya butuh bukti bahwa abstraksi tersebut benar-benar valid. Saya mengambil tiga proyek pribadi kecil dari arsip saya: sebuah alat pratinjau markdown, pelacak kebiasaan (habit tracker), dan sebuah landing page untuk sebuah acara. Tidak ada satu pun dari mereka yang berbagi framework atau struktur folder yang sama. Saya menginstal DTK secara lokal di masing-masing proyek dan mencoba menerapkan temanya.
Upaya pertama langsung gagal. Nama variabel yang dihasilkan DTK terlalu spesifik. Ia mengeluarkan token seperti --primary-action dan --background-overlay yang menyiratkan tata letak UI tertentu. Pada pratinjau markdown, nama-nama tersebut tidak masuk akal. Tidak ada tombol aksi. Tidak ada overlay. Saya mengubah logika generasinya untuk menghasilkan nama-nama struktural yang netral yang mendeskripsikan nilai, bukan widget.
Saya juga menemukan bahwa nilai default saya terlalu agresif. Ketika pengguna memasukkan konfigurasi yang tidak lengkap, DTK akan mengisi celah dengan nilai yang terlihat bagus di dashboard yang padat, tetapi rusak pada landing page yang renggang. Saya beralih ke default yang transparan di mana token yang hilang tidak akan dirender sama sekali, membiarkan proyek yang menggunakan DTK menentukan fallback mereka sendiri.
Lalu ada masalah dokumentasi. Apa yang tampak jelas bagi saya—"cukup masukkan objek konfigurasi"—terasa samar bagi seseorang yang membaca README di tengah malam. Saya menulis ulang dokumentasi tersebut dengan objek nyata, jalur file nyata, dan penjelasan yang jelas tentang apa yang terjadi saat Anda memanggil fungsi tersebut dibandingkan dengan apa yang perlu dilakukan aplikasi Anda setelahnya.
Proyek-proyek pribadi kecil ini bertindak sebagai tempat pengujian (test beds). Risikonya rendah, tetapi mereka mengekspos cacat nyata yang tidak akan saya temukan jika hanya menatap kode sumber secara terisolasi.
Ujian Sebenarnya: Produksi di Web Weavers World
Personal projects are sandboxes. They do not have deadlines, stakeholders, or legacy CSS that predates your package. The real test came when I integrated DTK into Web Weavers World, my business site. This was a live property with existing styles, client expectations, and analytics to consider. If the package broke something, I could not just delete the repo and start over.
I added DTK to the build pipeline, pointed it at a new color configuration, and let it generate a fresh set of CSS variables. The integration took an afternoon, not a week. That was the signal. Previously, adding a new theme meant writing new CSS, hunting down hardcoded hex values in twenty files, and hoping I did not miss an edge case. Now I add a palette to the configuration file, DTK generates the variables, and the rest of the site consumes them. The theme logic went from being a fragile manual process to something I trust enough to hand off to collaborators.
Three Questions That Changed How I Build
Going through this process forced me to formalize a mental checklist I now use before I abstract anything:
- Is this variable truly generic? If the name or the logic references a domain concept from the original project, it stays behind.
- Does this belong in the package or the application? Business rules, brand identities, and layout assumptions live in the app. Plumbing that generates standardized output lives in the package.
- Am I solving a reusable problem or a project-specific one? This is the hardest to answer honestly. We like to think our solutions are universal. Usually they are local.
Answering these questions forced me to simplify my design, often by removing code rather than adding it. DTK taught me that reuse is not a gift you give yourself. It is a discipline you practice by saying no to convenience.
A Different Way to Think About Refactoring
I used to measure refactors by how much shorter they made the code. Fewer lines felt like progress. Now I measure them by how many doors they open. The Dynamic Theme Kit is not elegant because it is concise. It is useful because it survived three unrelated personal projects and a production business site without needing to change its internals.
That is the metric that matters. Code that works once is an expense. Code that works repeatedly is an asset. Before I start any feature now, I stop. I ask if I am building something I will need again. If the answer is yes, I build it differently from the first line. I isolate the inputs. I define the outputs. I remove the assumptions.
The best refactor does not make your code shorter. It makes your code work in places you have not imagined yet.
