INCENTRO--11-FEBRUARI-20217011
Prabu Rangki

Prabu Rangki

Tech Lead

Kembali ke ringkasan
Blog

10 min baca

January 2, 2026

Dari Kekacauan Jadi Konsistensi: Meningkatkan pengalaman developer dengan alat internal (internal tools)

"Context switching" atau peralihan konteks jadi pembununuh senyap agensi digital. Satu hari, Anda membangung situs pemasaran di Astro, dan di hari berikutnya Anda berkemelut dengan web app menggunakan Vue dan TypeScript.

Sebagai Tech Lead di Incentro Asia Pacific, obsesi saya bukan cuma soal merilis kode, namun juga Pengalaman Developer (Developer Experience/DX). Kalau tim saya menghabiskan empat jam pertama memperdebatkan soal trailing commas atau menulis ulang format tanggal yang itu-itu saja, kita sudah kalah berperang.

Standardisasi dalam koding adalah hal yang krusial untuk membuat perangkat lunak (software) yang konsisten, berkualitas, dan mudah dikelola, dan bisa dilakukan dengan memastikan aturan seragam untuk struktur, gaya, dan praktik, untuk mendorong efisiensi tim, mempercepat orientasi, mengurangi eror, meningkatkan keamanan, dan menurunkan biaya-biaya jangka panjang. Hal tersebut juga membuat kode lebih mudah dibaca dan diprediksi oleh siapa saja sehingga mencegah kebingungan dan pengerjaan ulang, serta memastikan kepatuhan melalui best practices.

Itulah mengapa saya menganjurkan pendekatan radikal untuk standardisasi: memperlakukan perangkat internal kami layaknya produk sumber terbuka (open source).

Inilah cara kami melakukan standardisasi workflow supaya para developer bisa fokus untuk menyelesaikan masalah.

Kebijakan "Nol Debat": Unified Linting

Gesekan di dalam tim yang akan langsung terasa (atau terjadi) adalah gaya koding. Di dalam lingkungan agensi, gesekan ini akan diperparah ketika developer bergonta-ganti proyek. Bila Proyek A mengharuskan penggunaan tanda titik koma, sedangkan Proyek B melarangnya, otak Anda harus terus-menerus beradaptasi. Di dalam lingkungan agensi yang khas, memulai suatu proyek baru seringkali membawa kita ke "Configuration Bankruptcy". Anda menghabiskan hari pertama Anda bergelut dengan file konfigurasi, mencoba membuat Prettier bekerja dengan baik dengan ESLint, atau mencari tahu mengapa parser TypeScript mengalami masalah saat memproses file .vue. Selain itu, saat review kode, perdebatan soal estetika kode muncul, yang pada akhirnya malah memperlambat perilisan fitur-fitur baru.

Untuk menyelesaikan masalah ini, kami membuat @vinicunca/eslint-config. Konfigurasi ini didesain untuk melakukan lebih dari sekadar menerapkan code styling. Tujuan utamanya adalah mengurangi waktu dan upaya yang dihabiskan untuk pengaturan awal.

Berikut ini adalah rincian mengapa tool ini menjadi tulang punggung standardisasi kami:

Memecahkan Masalah "Poliglot"

Web development modern tidak hanya berkas-berkas JavaScript. Di dalam satu monorepo, bisa saja isinya terdiri dari:

  • Astro untuk laman pemasaran (marketing)
  • Vue atau Svelte untuk dasbor interaktif.
  • TypeScript yang menyatukan semuanya.

Mengonfigurasi ESLint untuk menangani file extensions (.astro, .vue, .svelte, .ts, .tsx) secara bersamaan adalah sebuah mimpi buruk. Anda harus mengatur beragam parser dan processor plugins. Kalau urutannya salah, maka linter akan crash.

Konfigurasi kami menyederhanakan kompleksitas ini dan secara otomatis mendeteksi isi proyeknya. Ketika file Vue terdeteksi, ia akan mengaktifkan aturan Vue. Jika mendeteksi Svelte, ia akan beralih konteks. Sehingga, developer tidak perlu mengetahui cara kerja parser, namun mereka hanya perlu tahu bahwa ketika mereka menekan "Simpan," kode tersebut akan diperbaiki.

Tinjauan Kode Berfokus pada Arsitektur, Bukan Sintaksis

Sebelum kami membangun ini, ulasan Pull Request kami dipenuhi dengan "nits", seperti:

  • "Tolong tambahkan koma di akhir kalimat ini."
  • "Impor harus diurutkan berdasarkan abjad."
  • "Jangan gunakan type apapun di sini."

Hal ini cuma menghabiskan waktu, dan menurunkan moral dan mengalihkan perhation dari loigika yang sebenarnya.

Dengan @vinicunca/eslint-config yang berperan sebagai "the Bad Cop", linter mampu mendeteksi masalah-masalah ini sebelum kode diunggah. Artinya, peninjauan kode yang dilakukan oleh manusia pun bisa fokus 100% pada:

  • "Apakah ini algoritma yang paling efisien?"
  • "Apakah ini akan menangani kasus khusus bagi pengguna?"
  • "Apakah arsitektur ini skalabel?"

Kami secara efektif mengotomatiskan bagian "sepele" pekerjaan Tech Lead sehingga kami dapat fokus pada "pembimbingan".

Lebih dari Sekadar Estetika: Kontrol Mutu & Keamanan Otomatis

Kami mengkonfigurasi preset supaya berfungsi sebagai alat analisis statis yang ketat. Preset ini tak hanya memeriksa indentasi, namun juga memeriksa kebocoran logika dan pola yang enggak aman:

  • Keamanan: Menandai pola berbahaya seperti v-html (di Vue) atau injeksi DOM yang tidak disanitasi yang dapat menyebabkan serangan XSS.
  • Type Integrity: Secara tegas melarang penggunaan apa pun di TypeScript sehingga memaksa developer untuk mendefinisikan struktur data mereka dengan jelas.
  • Best Practices: Mendeteksi "silent killer" seperti unused promises, perulangan tak terbatas dalam efek reaktif, atau penggunaan siklus hidup framework yang salah.

Dengan memasukkan aturan-aturan ini ke dalam config, kita mencegah developer junior dari kerentanan, dan kita menghentikan developer senior untuk bermalas-malasan dengan keamanan type.

Keuntungan DX: Ketika seorang developer bergabung ke dalam proyek baru, mereka enggak bertanya, "Apa aturannya di sini?" Mereka hanya perlu menjalankan linter. "Garis-garis merah" di editor kode mereka berperilaku persis sama di 100% basis kode kita.

Berhenti "Reinventing the Wheel": Utility belt bersama

Pada masa-masa awal, saya memperhatikan suatu pola yang terbentuk. Di tiap proyek baru, developer akan membuat utils/ atau direktori helpers/ yang biasa saya sebut sebagai "Kuburan Folder Utils". Di dalamnya, developer akan menulis function yang sama yang kita gunakan di sepuluh proyek ke belakang, seperti string sluggifier, pemformat mata uang, validator email, atau deep-merge function.

Ini adalah utang teknis (technical debt) yang terselubung. Kalau kita menemukan bug pada validator email di Proyek A, maka Proyek B tetap rusak.

Hal ini akan menimbulkan tiga masalah besar:

  1. Inkonsistensi: Validator email Proyek A menerima, tetapi validator Proyek B menolaknya.
  2. Bugs Tersembunyi: Function salin-tempel yang "cepat" ini jarang mendapatkan pengujian unit karena dianggap sebagai "pembantu kecil".
  3. Waktu Terbuang: Kita membayar developer senior untuk—lagi-lagi—menulis ulang logika isObject untuk ke-50 kalinya.

Solusi kami adalah @vinicunca/perkakas.

Ini bukan koleksi script sembarangan, namun merupakan “Standard Library” kami. Jadi, kenapa perubahan ini penting untuk Developer Experience?

Sudah Teruji di Medan Perang

Di dalam proyek klien pada umumnya, fungsi utilitas sering luput dari perhatian selama pengujian kualitas (QA). Jika fungsi pembantu (helper function) gagal pada edge case (misalnya, memformat tanggal null), maka aplikasi produksi akan mengalami crash.

Dengan memindahkan functions ke @vinicunca/perkakas, kami membalikkan risiko. Library ini sudah diuji ketat dengan vitest.

  • Ketika kita menambahkan satu function ke perkakas, kita menulis tes untuk setiap edge case yang bisa kita pikirkan.

Saat seorang developer mengimpor sebuah function, ia tidak akan mengharapkan itu akan berfungsi, melainkan mereka tahu kalau functionnya akan bekerja karena telah lolos dari pipeline CI/CD dari library itu sendiri.

Dukungan TypeScript Kelas Satu

Tak ada hal yang membunuh alur developer selain mengimpor sebuah library dan melihat Could not find a declaration file for module....

@vinicunca/perkakas 100% ditulis dengan TypeScript sehingga memberikan dorongan DX langsung:

  • Intellisense: Begitu seorang developer menuliskan import { ... } from, IDE mereka menyarankan tools yang tersedia.
  • Type Guards: Kami banyak menggunakan type predicates. Kalau Anda menggunakan check functions kami, TypeScript secara otomatis mempersempit type tersebut sehingga mencegah kesalahan "undefined is not a function" di tahap selanjutnya.
Efek "Upstream"

Bagian terbaik dari sistem ini adalah penanganan perbaikan bug-nya. Kalau kita menemukan bug dalam utility function di dalam Proyek A, kita tidak hanya memperbaikinya di sana. Kita memperbaikinya di @vinicunca/perkakas, merilis versi baru, dan kemudian cukup memperbarui package di Proyek B, C, dan D.

Kami menyelesaikan masalah hanya satu kali, dan setiap proyek yang kita kelola langsung jadi lebih baik. Efisiensi sejati dari sistem terpusat ini terlihat jelas dalam pendekatannya terhadap pemeliharaan dan, yang terpenting, perbaikan bug. Bayangkan skenario tipikal tanpa sistem ini: fungsi utilitas umum diduplikasi di Proyek A, Proyek B, Proyek C, dan Proyek D. Kalau ada cacat ditemukan pada versi utilitas di Proyek A, perbaikan langsung—dan seringkali satu-satunya—dilakukan secara lokal di Proyek A. Para developer untuk Proyek B, C, dan D tetap tidak menyadarinya, dan bug tersebut tetap ada, menunggu untuk menyebabkan masalah di aplikasi lain.

Sistem kami, secara fundamental, mengubah proses yang kacau ini. Ketika kami menemukan bug di dalam utility function yang sedang digunakan, misalnya, di dalam Proyek A, kami sengaja tidak memperbaikinya hanya di dalam codebase proyek spesifik tersebut. Sebaliknya, kami melacak sumber masalah tersebut kembali ke satu-satunya sumber yang berwenang: utility library bersama core kami, @vinicunca/perkakas.

Dampak dari pendekatan ini sangat transformatif. Kami menyelesaikan masalah sekali saja, dan hanya sekali, langsung dari akarnya. Tiap proyek yang saat ini kami kelola, dan setiap proyek baru yang mengadopsi central package langsung terlindungi dari bug tersebut. Hal ini meniadakan pekerjaan yang berulang-berulang sehingga mencegah munculnya kembali kesalahan yang sudah diketahui, dan menjamin standar kualitas yang konsisten dan tinggi di seluruh portofolio aplikasi kami. Hasil akhirnya adalah pengurangan besar dalam utang teknis dan peningkatan dramatis dalam Developer Experience karena waktu dihabiskan untuk membangun fitur baru daripada mengejar masalah lama yang sama di berbagai repositori.

The Next Horizon: Standar "Headless" UI

Dengan Code Style (Linting) dan Logic (Utilities) terstandardisasi, tantangan selanjutnya yang akan kami adalah adalah Interface.

Di dalam agensi, tiap klien ingin tampilan dan nuansa yang unik. Klien A ingin estetika sharp-edged brutalistis; Klien B menginginkan desain yang lembut, membulat, dan seperti kaca. Karena visualnya sangat berbeda, setiap kali, kami terjebak dalam perangkap membangun kembali komponen dari awal.

Kami menyadari bahwa meskipun style-nya berubah seratus persen setiap saat, perilakunya hampir selalu sama. Dialog selalu perlu menangkap fokus. Dropdown selalu perlu ditutup waktu Anda klik di luarnya. Combobox selalu membutuhkan navigasi keyboard.

Kita sedang merancang Internal "Headless" UI Library.

Konsepnya: Logic First, Style Last

Tujuannya adalah untuk membangun library komponen tanpa style dan function, "rangka" dari UI kami.

  • Library menangani: manajemen status, atribut ARIA, aksesibilitas kibor, manajemen fokus, dan event listeners.
  • Developer menangani: The CSS.
Why This Changes the Game
  1. Memisahkan desain dari engineering: Developer takkan membuang-buang waktu berhari-hari untuk menciptakan kembali logika dari Accordion. Mereka akan mengimpor <UnstyledAccordion /> dan menerapkan branding klien lewat props atau kelas CSS.
  2. Aksesibilitas secara default: Aksesibilitas (a11y) sangat sulit dicapai dengan benar. Dengan memusatkan logika komponen, kami memastikan kalau tiap proyek yang kami rilis dapat diakses langsung. Kalau kami memperbaiki screen-reader bug di library, tiap proyek klien akan menerima manfaatnya.
  3. Kebebasan kreatif tertinggi: Enggak seperti menggunakan pre-styled library, seperti UI atau Bootstrap—yang harus Anda perjuangkan untuk override—headless library tidak mengasumsikan apapun soal desain. Namun, memungkinkan tim frontend kami untuk mengimplementasikan desain terliat yang dibuat oleh tim kreatif kami tanpa harus berurusan dengan coding.

Ini adalah kepingan terakhir dari teka-teki: memungkinkan developer kami untuk fokus sepenuhnya pada "seni" dari frontend, karena "ilmu"-nya sudah ditangani oleh tools kami.

Hasilnya

Pergeseran dari praktik pengembangan yang terisolasi dan spesifik ke model "Internal Open Source" terpadu telah membentuk kembali budaya engineering dan hasil rekayasa kami secara mendalam. Dengan memperlakukan standar, konfigurasi, dan common utility library kami sebagai proyek sumber open source—dengan pengelola khusus, dokumentasi yang jelas, dan proses kontribusi formal—kami telah membuka efisiensi yang memberikan dampak ke seluruh organisasi.

Sejak menerapkan strategi ini, kami telah melihat peningkatan nyata di beberapa area utama:

  1. Pengaturan dan standardisasi lebih cepat: Era panduan pengaturan yang kompleks dan spesifik untuk tiap proyek sudah berakhir. Cukup dengan pnpm install, Anda dapat menggunakan seluruh perangkat standar organisasi, termasuk linter, formatter, membuat script, dan core utility packages. Standardisasi instan ini menghilangkan "penyimpangan konfigurasi" dan memastikan setiap proyek dimulai dengan fondasi yang kokoh dan konsisten.
  2. Proses orientasi yang lancar dan beban kognitif yang berkurang: Karyawan baru enggak perlu lagi menavigasi labirin gaya pengkodean dan pilihan teknologi yang berbeda di berbagai tim. Mereka mempelajari cara kerja kami sekali saja, dan pengetahuan serta perangkat dasar tersebut dapat diterapkan di mana saja, mulai dari microservice terkecil hingga aplikasi front-end terbesar. Hal ini secara dramatis mempersingkat waktu hingga time-to-first-commit dan memungkinkan developer untuk fokus pada logika bisnis daripada boilerplate.
  3. Kualitas lebih tinggi lewat perbaikan terpusat: Ketika seorang developer di Tim A menemukan bug dalam core utility function atau menemukan edge case dalam konfigurasi ESLint bersama, perbaikan mereka tidak terbatas pada tim mereka saja. Bug yang diperbaiki dalam tooling kami langsung diperbaiki untuk semua orang di semua proyek yang bergantung pada shared package tersebut. Akuntabilitas kolektif dan pemeliharaan terpusat ini menciptakan lingkaran feedback yang kuat sehingga meningkatkan kualitas kode secara eksponensial dan lebih cepat daripada di lingkungan yang terisolasi.
  4. Memungkinkan praktik terbaik tingkat lanjut: Dengan menyediakan tool berkualitas tinggi dan telah diverifikasi sebelumnya (seperti pustaka pencatatan terstandarisasi atau pembungkus otentikasi yang aman), kami mempermudah developer untuk mengikuti praktik terbaik daripada menciptakan solusi mereka sendiri yang tidak aman atau berkinerja buruk. "The paved road" menjadi jalan yang paling mudah dilalui.

Kesimpulan

Teruntuk para Tech Lead, Engineering Manager, atau Principal Engineer yang membaca ini:
Lihatlah folder utils Anda dengan saksama. Teliti lagi .eslintrc Anda, file konfigurasi CI/CD, dan petunjuk pengaturan templat atau boilerplate. Kalau Anda melihat core logic yang sama, regex yang sama untuk validasi input, atau aturan lint khusus yang sama disalin dan ditempel di lebih dari tiga repositori yang berbeda, Anda tidak hanya memiliki masalah, tetapi juga peluang luar biasa untuk membangun internal tools. Mengabstraksikan shared logic ke dalam sebuah paket yang terawat dan memiliki versi adalah langkah pertama untuk mengubah kekacauan menjadi konsistensi. Diri Anda di masa depan, serta waktu dan beban pemeliharaan yang tak terhitung jumlahnya yang akan Anda hemat, pasti akan berterima kasih kepada Anda.