Migrasi Legacy PHP ke Go: Kenapa, Bagaimana, dan Pelajarannya

4 April 2026 oleh Faiq Najib


Saya pernah berada di posisi di mana codebase PHP sudah kepenuhan, fitur baru makin susah ditambah, bug makin sering muncul, dan setiap deploy terasa seperti melempar koin. Bukan karena PHP jelek, tapi karena sistem yang dibangun bertahun-tahun tanpa arsitektur yang jelas akhirnya menyusahkan dirinya sendiri. Pernah waktu itu sampai harus rollback tiga kali dalam sehari gara-gara deploy yang harusnya simple. Stress level-nya… hadeh, jangan ditanya hahaha.

Nganu, jadi tulisan ini bukan “Go lebih baik dari PHP” atau “PHP sudah mati”. Bukan. Tulisan ini catatan pengalaman saya melakukan migrasi sistem backend dari PHP (CodeIgniter 3 dan Laravel) ke Go, berdasarkan proyek nyata yang saya kerjakan. Bukan tutorial, bukan juga propaganda. Cuma catatan pribadi aja, siapa tahu ada yang lagi ngalamin hal serupa dan bisa ambil pelajaran dari kesalahan-kesalahan saya hehe~

Masalahnya Bukan Bahasa, Tapi Arsitektur #

Sistem yang saya tangani punya profil seperti ini:

Masalah sebenarnya bukan di bahasa pemrogramannya. PHP itu bagus kok. Masalahnya ada di:

  1. Tidak ada pemisahan layer: controller langsung query ke database, business logic bercampur dengan presentation logic. Pokoknya kayak nasi goreng yang isinya macem-macem, tapi nggak tau mana nasi mana sayurnya hahaha.
  2. Sulit di-test: kode yang tightly coupled bikin unit testing jadi nightmare. Mau test satu function, eh harus setup database, mock tiga dependency, dan berdoa semoga berhasil.
  3. Developer experience menurun: onboarding developer baru makin lama, bug fix makin berisiko. Terakhir ada developer baru yang sampai bilang, “Mas, ini kodenya… ehem, menarik sekali arsitekturnya.”, Translation: chaotic hehe~

Intinya, sistem ini butuh bukan sekadar ganti bahasa, tapi re-architect.

Kenapa Go? #

Kalau ditanya kenapa tidak refactor saja di PHP, jawabannya: bisa saja. Tapi dalam kasus ini, ada beberapa alasan kenapa Go jadi pilihan yang lebih tepat. Bukan karena saya lagi hypnotized sama hype Go, tapi karena ada pertimbangan yang cukup matang (setidaknya menurut saya sih hehe):

1. Type Safety Menghemat Waktu Debug #

PHP itu dynamically typed2, yang artinya banyak bug baru ketahuan saat runtime. Go dengan static typing-nya menangkap error saat compile time. Sederhana, tapi dampaknya besar, bug yang biasanya baru muncul di production sekarang ketahuan saat build. Dan percayalah, tidur lebih nyenyak kalau tau bug type-related nggak bakal tiba-tiba muncul jam 2 pagi hahaha.

2. Concurrency untuk Free #

Sistem ini menangani banyak request simultan, mulai dari tracking GPS real-time hingga report generation. Goroutine di Go membuat concurrent programming jadi jauh lebih simpel dibanding approach lain yang pernah saya coba. Serius deh, pertama kali pakai goroutine itu rasanya kayak, “Kok bisa se-simpel ini?” hehe~

3. Deployment yang Bersih #

Satu binary. Tanpa dependency hell, tanpa composer install di server, tanpa PHP version conflict. Build di lokal, deploy satu file. Done. Sederhana tapi powerful. Dulu deploy PHP itu harus pastiin dulu composer dependencies terinstall dengan benar, PHP version cocok, extension ini itu ada… sekarang tinggal scp satu file, done. Simple life is the best life hehe.

4. Performance yang Terukur #

Bukan soal benchmark angka, tapi soal penggunaan resource yang predictable. Memory usage Go yang konsisten membuat kapasitas planning jauh lebih mudah. Dulu sistem PHP bisa tiba-tiba memory spike tanpa sebab yang jelas. Sekarang memory usage-nya flat dan predictable. Peace of mind, priceless hahaha.

Bukan berarti Go sempurna, error handling-nya verbose (semua if err != nil itu… well, you get used to it)3, dan ecosystem-nya lebih kecil dari PHP. Tapi untuk use case ini, trade-off-nya sepadan. Setiap tool punya kelebihan dan kekurangan, tinggal kita pintar-pintarnya milih yang paling cocok aja hehe~

Pendekatan Migrasi: Per-Module, Bukan Big Bang #

Salah satu kesalahan terbesar dalam migrasi adalah “kita rewrite semuanya dari nol”. Saya pernah dengar cerita horor tentang tim yang spend 2 tahun untuk big-bang rewrite dan akhirnya… tidak jadi. Alasannya macem-macem: burn out, scope creep, atau business requirement yang berubah di tengah jalan. Amit-amit deh kalau sampai kejadian kayak gitu hahaha.

Pendekatan yang saya pakai:

1. Pemetaan Modul #

Pertama, map semua endpoint dan entity ke dalam modul-modul yang jelas. Dari 370+ endpoint, saya mengelompokkannya menjadi beberapa domain: authentication, tracking, reporting, user management, dan seterusnya. Prosesnya… yah, cukup tedious. Butuh waktu beberapa hari cuma buat bikin spreadsheet yang berisi mapping semua endpoint. Tapi percayalah, langkah ini worth it banget hehe.

2. Service–Repository Pattern #

Setiap modul di-design dengan pola service–repository:

Kenapa dipisah? Karena dengan pemisahan ini:

Sederhananya, kita bikin layer yang jelas sehingga concern masing-masing bagian tidak mixed up. Awalnya sih terasa over-engineering, tapi setelah jalan beberapa bulan, oh man, ini sangat membantu hehe~

3. Satu Endpoint pada Satu Waktu #

Prosesnya kurang lebih:

  1. Ambil satu endpoint dari PHP
  2. Tulis test case berdasarkan behavior yang sudah ada4
  3. Implementasi di Go dengan pola service–repository
  4. Test sampai pass
  5. Deploy dan monitor
  6. Ulangi

Ya, memang lambat. Tapi predictable. Setiap migrasi endpoint adalah incremental progress yang terukur. Dan yang paling penting, stakeholder bisa lihat progress secara nyata. “Minggu ini berhasil migrasi 5 endpoint” itu lebih meyakinkan daripada “kami masih ngerjain migrasi” selama berbulan-bulan tanpa hasil yang terlihat hehe.

Hasil yang Terukur #

Beberapa angka dari proyek ini:

Yang tidak terukur tapi sangat terasa: peace of mind saat deploy. Tidak ada lagi feeling “semoga kali ini tidak ada yang break”. Sekarang deploy itu… yah, tetap deg-degan dikit sih, tapi nggak sampai bikin susah tidur hahaha.

Pelajaran #

Beberapa hal yang saya pelajari dari proses ini:

1. Pahami Dulu Sistem yang Ada #

Sebelum menulis satu baris pun kode Go, saya spend waktu cukup lama untuk memahami behavior sistem yang sudah ada. Bukan membaca code-nya saja, tapi memahami mengapa keputusan tertentu dibuat di masa lalu. Kadang, kode yang terlihat “aneh” punya alasan yang masuk akal di konteks saat itu dibuat. Jangan langsung judge kode legacy sebagai kode jelek. Siapa tahu dulu ada constraint tertentu yang memaksa keputusan itu diambil hehe~

2. Big Bang Rewrite itu Trap #

Kalau bisa sedikit-sedikit, ngapain langsung semua? Pendekatan incremental memang terasa lambat, tapi risikonya jauh lebih kecil. Setiap endpoint yang berhasil dimigrasi adalah progress yang bisa ditunjukkan ke stakeholder. Dan yang penting, sistem tetap jalan normal selama proses migrasi. Business as usual, gitu deh hehe.

3. Test Dulu, Migrasi Kemudian #

Menulis test untuk sistem legacy itu membosankan, ya? Tapi test adalah jaring pengaman yang memastikan behavior sistem setelah migrasi tetap sama. Tanpa test, kamu tidak migrasi, kamu berjudi. Dan percayalah, deploy dengan test coverage yang bagus itu jauh lebih relaxing daripada deploy sambil berdoa hahaha.

4. Jangan Prematurely Optimize #

Awalnya saya tergoda untuk langsung pakai microservices, message queue, dan arsitektur fancy lainnya. Tapi reality check: sistem yang belum stabil arsitekturnya tidak butuh microservices, butuh fondasi yang kuat. Monolith yang well-structured lebih baik daripada microservices yang chaotic. KISS (Keep It Simple, Stupid)6 itu beneran wisdom yang timeless hehe~

Penutup #

Migrasi dari PHP ke Go bukan tentang “bahasa A lebih baik dari bahasa B”. Tapi tentang memilih tool yang tepat untuk masalah yang dihadapi, dan dalam kasus ini, Go dengan static typing, concurrency model, dan deployment simplicity-nya adalah pilihan yang tepat.

Apakah semua sistem PHP harus dimigrasi ke Go? Enggak lah. Kalau sistem PHP-mu jalan dengan baik, arsitekturnya jelas, dan tim nyaman pakai PHP, ya udah, lanjutkan. Jangan migrasi cuma karena ikut-ikutan hype. Migrasilah karena ada clear business value dan measurable benefit-nya hehe~

Kalau kamu punya sistem legacy yang mulai kepenuhan dan ingin mendiskusikan pendekatan migrasi yang tepat, hubungi saya. Atau lihat layanan yang bisa saya bantu.


Tag: go · php · arsitektur · migration


  1. Serius, saya sendiri sempat double-check angkanya waktu pertama kali ngitung. Ternyata memang segitu banyak hahaha. ↩︎

  2. PHP 7+ memang sudah punya type hints dan strict types, tapi tetap tidak se-strict Go yang static typed sejak awal. ↩︎

  3. Di awal-awal pakai Go, saya sempat annoyed sama banyaknya if err != nil. Tapi setelah terbiasa, ya udah accept aja. Lagian lebih baik verbose tapi jelas daripada concise tapi error handling-nya hidden↩︎

  4. Menulis test berdasarkan behavior yang ada itu penting. Jangan sampai migrasi malah mengubah behavior yang sudah diharapkan user↩︎

  5. Migrasi dari MySQL ke PostgreSQL itu cerita tersendiri. Someday mungkin saya tulis juga hehe. ↩︎

  6. Keep It Simple, Stupid, prinsip yang sering dilupakan saat kita terlalu excited sama teknologi baru. ↩︎