Automatic Data Seeding & Data Migration Aplikasi Go(lang) pada Heroku
Pendahuluan
Sebagai backend developer, tentu saja kita tidak bisa terlepas berurusan dengan database, terutama mendefinisikan/mengubah skema dari database yang ingin kita buat serta mempopulasi data pada database sehingga mempermudah pengujian. Kedua aktivitas tersebut dapat didefinisikan sebagai data migration (proses mendefinisikan/mengubah skema atau rancangan data dari database) dan data seeding(proses mempopulasi database dengan sekumpulan data). Proses data migration ini tentu saja masih bisa dilakukan secara manual apabila skema yang dirancang mempunyai entitas data yang sedikit dengan menggunakan query SQL. Namun bayangkan apabila jenis entitas tersebut banyak. Tentu saja akan memakan banyak waktu & tenaga apabila dilakukan dengan mengeksekusi query SQL satu per satu. Begitupun untuk data seeding. Bayangkan apabila terdapat banyak data yang ingin dipopulasikan sebagai data awal pada aplikasi. Tentu saja akan memakan waktu & tenaga untuk memasukkan data tersebut satu per satu dengan menggunakan query SQL Untungnya, terdapat cara otomatis (untuk data seeding tidak bisa dibilang sepenuhnya otomatis) untuk melakukan proses data migration & seeding. Pada artikel ini Saya akan membahas cara mengotomasi proses data migration & seeding untuk aplikasi web service go yang berjalan di Heroku.
Data Migration
Untuk proses data migration sendiri sebenarnya terdapat dua proses yakni migrate up dan migrate down. Perbedaan keduanya adalah, migrate up akan memperbarui skema database dengan menggunakan skema terbaru sedangkan migrate down akan melakukan rollback atau mengembalikan skema database ke skema sebelumnya. Untuk pembahasan kali ini, saya akan bagaimana proses melakukan migrate up secara otomatis, karena proses migrate up menurut saya paling sering terjadi pada proses deployment sehingga sangat memungkinkan untuk diotomasi. Saya dan backend developer lain (Galang dan Akbar) pada kelompok For Future Use menggunakan library GORM untuk memudahkan proses penulisan kode query database pada Go(lang). Library tersebut sudah menyediakan method bernama AutoMigrate. Method ini akan melakukan proses migration terhadap suatu entitas database. Dengan ini maka idenya adalah kita perlu membuat suatu metode yang mengeksekusi AutoMigrate untuk semua entitas yang akan digunakan pada database ketika kode pertama kali dijalankan. Dengan metode tersebut, maka kita tidak perlu membuat tahap inisialisasi database pada heroku (Mendefinisikan schema yang digunakan dengan mengeksekusi query, Membuat Table, dsb) karena semua hal tersebut sudah ditangani oleh method AutoMigrate. Sebagai contoh, saya akan mengambil contoh implementasi pada proyek PPL kami bagaimana melakukan proses data migration untuk entitas User. Sebagai catatan, entitas User menyimpan data yang berkaitan dengan pengguna website seperti email, password, role, status, dan nama.
Katakanlah kita ingin memigrasi user tersebut pada server heroku sehingga skema user berhasil didefinisikan pada database heroku, maka langkah selanjutnya adalah kita perlu method yang berguna untuk menghubungkan web service dengan database. Berikut merupakan kode proses inisialisasi database server pada proyek kelompok kami.
Terlihat bahwa method di atas akan mendefisikan parameter seperti username, password, nama database yang ingin digunakan, dan host dari server. Lalu atribut-atribut tersebut akan dijadikan parameter untuk menghubungkan database server. Pada heroku sendiri, url dari database server sudah disediakan oleh heroku dan dapat berubah setiap waktu. Url tersebut tersimpan environment variable bernama DATABASE_URL. Oleh karena itu pada kode tersebut, akan dilakukan pengecekan terlebih dahulu nilai dari DATABASE_URL dan apabila DATABASE_URL tersebut belum didefinisikan, maka bisa menggunakan parameter yang sebelumnya sudah didefinisikan. Method tersebut akan mengembalikan instance database yang sudah terkoneksi dengan web service.
Setelah berhasil terkoneksi dengan database server, maka langkah selanjutnya adalah membuat method untuk melakukan proses migrasi untuk semua entitas. Berikut merupakan potongan kode yang Saya ambil dari proyek PPL kami.
Method tersebut akan melakukan proses migrasi untuk semua entitas yang digunakan pada database, salah satunya adalah entitas User. Untuk entitas User, maka proses migrasi ini akan mendefinisikan skema entitas User yang memiliki atribut Email, Name, Password, Role, Status (sebagai catatan, gorm:- akan mengeksklusi suatu atribut dari skema entitas database sehingga atribut yang mempunyai parameter “gorm:-” akan dieksklusi sebagai atribut entitas database) pada database.
Proses inisialisasi tersebut secara keseluruhan tergabung pada method berikut.
Seperti yang disebutkan sebelumnya, method tersebut akan dipanggil pada main.go. Kode tersebut akan digunakan untuk mulai menjalankan web service golang.
Terlihat bahwa metode untuk menginisialisasi database (InitDB) akan dipanggil terlebih dahulu sebelum proses menjalankan web service dieksekusi. Karena main.go merupakan kode yang dieksekusi ketika aplikasi sudah di-deploy ke server heroku, maka otomatis method untuk migration juga akan terpanggil sebelum proses eksekusi web service sehingga proses data migration akan dilakukan secara otomatis tanpa harus perlu mengeksekusi query SQL pada postgreSQL heroku. Table User akan dapat terlihat pada postgreSQL heroku setelah kode main.go berhasil dijalankan.
Data Seeding
Setelah mengetahui bagaimana cara melakukan proses data migration, maka selanjutnya Saya akan membahas bagaimana cara melakukan data seeding dengan menggunakan kode golang untuk proses seeding. Saya akan mengambil contoh seeding data penetapan hari sidang. Berikut merupakan struktur skema dari entitas penetapan hari sidang.
Dari skema terlihat bahwa kita perlu menghasilkan informasi nomor perkara, nama terdakwa, nama majelis hakim, dan sebagainya (kecuali Pengaju karena Pengaju merupakan entitias lain berupa User di database) untuk membuat satu entitas penetapan hari sidang. Lalu dari situ, bila diperhatikan terdapat 4 jenis data yang digunakan yakni string, string array, integer, dan datestring (merupakan string tanggal dengan format YYYY(tahun)-MM(bulan)-dd(tanggal)). Oleh karena itu untuk melakukan seeding, kita akan men-generate keempat jenis atribut secara acak dan dengan memerhatikan constraint dari gorm pada atribut (seperti varchar(30) berarti maksimal memiliki panjang 30 karakter pada string). Berikut merupakan kode untuk melakukan data seeding untuk entitas penetapan hari sidang yang kami gunakan pada proyek PPL kami.
Kode tersebut terletak pada package main sehingga kode bisa dijadikan kode tersendiri yang bisa dieksekusi secara terpisah dari main. (bisa dijalankan dengan cara go run penetapan_hari_sidang_seeding.go). Selain itu, pada proses build, setiap potongan kode yang menggunakan fungsi main dan tergabung dalam satu package main akan dianggap sebagai kode tersendiri sehingga proses build yang dilakukan akan terpisah dari main.go sehingga nantinya akan dihasilkan binary yang terpisah dari main sehingga binary tersebut bisa dieksekusi melalui terminal heroku. Sekarang Saya akan membahas bagaimana seeding dilakukan.
- Pada fungsi main, akan dilakukan proses mengkoneksi aplikasi dengan database server dengan InitDB. (Line 61)
- Setelah terhubung dengan database server, langkah selanjutnya adalah mendefinisikan repository. Repository inilah yang mengeksekusi query database yang berkaitan dengan entitas penetapan hari sidang (Line 62).
- Melakukan seeding sebanyak 10000 data penetapan hari sidang (line 66–74). Besar datanya (nilai NData) tentunya perlu disesuaikan dengan kapabilitas dari database server dan juga keinginan.
- Mendefinisikan satu entitas data penetapan hari sidang (Line 67). Baris ini akan memanggil getValidPenetapanHariSidang yang mengisi atribut-atribut dari instance entitas penetapan hari sidang dengan data yang valid secara acak (kecuali untuk id pengaju dan dokumen penetapan hari sidang). Pada atribut NamaMajelisHakim, NamaPaniteraPengganti, maka akan digunakan data nama valid yang dihasilkan secara acak. Pada atribut NamaTerdakwa (string array), maka akan digunakan array yang berisikan daftar nama dengan panjang array yang bervariasi. Lalu untuk nomor perkara akan dihasilkan string dengan format nomor surat perkara secara acak. Dan untuk elemen tipe terakhir yakni TanggalPenetapanSidang & TanggalHariSidangPertama(datestring) akan dihasilkan string tanggal dengan format “YYYY(tahun)-MM(bulan)-dd(tanggal)” secara acak.
- Setelah diperoleh satu instance penetapan hari sidang yang valid, maka langkah selanjutnya yang dilakukan adalah memasukan instance tersebut ke database dengan memanfaatkan repository. Method create pada repository akan melakukan query “INSERT” instance tersebut ke database postgreSQL yang sudah terhubung. (Line 68).
Setelah didefinisikan standalone code untuk melakukan seeding penetapan hari sidang, maka langkah selanjutnya adalah membuat procfile. Hal ini perlu dilakukan karena script binary yang dihasilkan oleh proses build dari heroku yang dilakukan sebelum menjalankan server tidak hanya binary dari main.go saja, melainkan binary dari kode untuk melakukan seeding. Oleh karena itu, kita perlu memberi tahu dyno web (worker pada heroku yang berguna untuk menjalankan web server) binary mana yang digunakan untuk menjalankan web service (binary dari main.go). Perlu dicatat bahwa proses build pada go di heroku akan menghasilkan binary yang tersimpan pada direktori bin seperti yang pada gambar berikut.
Seperti yang terlihat pada gambar, heroku akan mendeteksi source code mana yang berada di main package lalu akan melakukan build masing-masing dari semua source code tersebut menjadi binary yang bisa dieksekusi secara terpisah. Terlihat bahwa nama binary yang dihasilkan merupakan nama direktori terdalam yang menyimpan source code. main.go tersimpan pada paperless-backend sedangkan kode seeding untuk penetapan hari sidang tersimpan di penetapan_hari_sidang sehingga secara berurutan, masing-masing binary akan tersimpan di direktori bin sebagai paperless-backend dan penetapan_hari_sidang. Maka kita perlu mengarahkan dyno web untuk menjalankan binary dari main.go yakni bin/paperless-backend pada procfile. Berikut merupakan procfile yang digunakan pada proyek PPL kami.
Dengan procfile tersebut, maka dyno web akan mengeksekusi bin/paperless-backend setelah proses build berhasil dijalankan sehingga web service dapat berjalan di heroku. Setelah itu, untuk melakukan seeding data pada heroku server maka yang perlu dilakukan adalah mengeksekusi binary untuk seeding penetapan hari sidang pada bash heroku server dengan script berikut. Untuk kasus ini saya menggunakan commands berikut
$ heroku login #login ke heroku
$ heroku run bash -a <nama-aplikasi> #Masuk ke terminal aplikasi heroku$ cd bin #Masuk ke direktori bin
$ ./penetapan_hari_sidang #Mengeksekusi binary penetapan_hari_sidang
Setelah kode tersebut dieksekusi maka voila, Anda berhasil mempopulasi data penetapan hari sidang pada database heroku.
Penutup
Proses data migration & data seeding berguna untuk memudahkan backend developer untuk mengganti skema data dan juga mempopulasi data. Proses populasi data akan memudahkan backend developer untuk menguji performa, skalabilitas aplikasi karena database sudah terisi dengan data. Bagi frontend developer, database aplikasi yang sudah terpopulasi memudahkan pengecekan apakah implementasi integrasi frontend & backend sudah berhasil dilakukan. Kedua hal tersebut ternyata cukup mudah dilakukan pada golang dengan adanya library GORM, build aplikasi golang yang akan menghasilkan binary program yang bisa dieksekusi secara native, serta proses build heroku yang cukup canggih untuk mendeteksi program mana yang perlu dijadikan sebagai binary. Sekian penjelasan dari Saya, mudah-mudahan dapat bermanfaat.