Ini yang Kamu Butuhkan untuk Membuat Kodemu Rapi – Service Object di Ruby on Rails

Tutorial dasar Ruby on Rails seringnya mengangkat studi kasus yang simpel yang tentu saja tidak mengherankan jika kode programnya pun simpel. Contoh paling populer adalah aplikasi yang melakukan CRUD ke satu tabel, tabel books misalnya. Di aplikasi seperti ini, kita hanya akan menemukan kode Ruby yang penting di kelas model Book dan kelas controller BooksController.

Tipikal aplikasi contoh seperti ini adalah semua business logic berada di controller. Contoh :

Untuk pemula, kode seperti ini memang patut diperkenalkan karena menunjukkan betapa mudahnya membuat sesuatu menggunakan Ruby on Rails. Selain itu, business logic aplikasi ini khususnya method create hanyalah membuat record di tabel books. Sesimpel itu, jadi buat apa dibuat rumit, nanti yang baru belajar malah mabok duluan *eh

Kompleksitas meningkat ketika business logic aplikasi tidak sesimpel crud ke satu tabel. Kita ambil contoh studi kasus langganan premium membership di IDRails.



Saya sedang menyiapkan fitur premium membership di IDRails. Dengan jadi member premium kamu memiliki akses ke video-video premium yang menitikberatkan ke studi kasus. Selain itu punya akses juga untuk men-download materi.

Ketika ada user yang mendaftar menjadi premium member maka kita perlu me-record data subscription ke tabel dengan sebelumnya membuat beberapa komputasi. Ketika semua ditumpahkan ke controller, hasilnya campur aduk seperti ini.

Kode di atas masih terlihat berantakan padahal untuk melakukan generate kode unik sudah dipisah ke private method, bayangkan kalau itu ditumpahkan juga di method create.

Di method create juga belum ada validasi apakah package yang dipilih berdasarkan parameter package_id valid atau enggak. Biar kode kita robust, tentu perlu ditambah validasi.

Uwaw, tambah semrawut lagi kodenya.

Ga enaknya menumpahkan semua business logic aplikasi di controller adalah, well, ya jelas berantakan. Keberantakan ini membuat kode susah dimengerti, ribet untuk dibuat automated test-nya (mesti ngetes controller) dan tidak secara eksplisit menjelaskan maksud / intention dari business logic nya.

Sekarang bandingkan dengan kode yang ini.

Selain lebih pendek yang menyebabkan readable, kode versi yang ini secara eksplisit menjelaskan kalau create pada ujung-ujungnya adalah membuat data subscription (terlihat dari nama method create_subscription. Di samping itu, kalau kita mau membuat automated test maka yang kita buat adalah tes untuk si create_subscription ini, jadi ga perlu ngetes controller kalau yang dites adalah logika pembuatan subscription.

Oke sip, terus PremiumService.create_subscription implementasinya gimana?

Ga ribet, bisa dibilang cuma mindah yang tadinya ada di controller ke sebuah kelas tersendiri yang dari namanya kita bisa langsung tahu kelas ini ngapain. Jadi dari sini bisa diambil pemikiran kalau service object adalah apa yang menggambarkan business process dari aplikasi. Dengan melihat kelas-kelas service kita bisa tahu aplikasi kita itu ngapain.

Salah satu ciri service object di Rails adalah penamaan kelasnya yang menggunakan kata kerja dan hanya memiliki satu public method, biasanya bernama perform atau call, bisa juga process.

Kode ini lokasinya di mana? di folder services yang ada di bawah folder app. Di dalamnya bebas kalau mau ada folder lagi seperti kasus kelas Create di atas. Dari nama module berati lokasinya ada di app/services/premium_service/subscription/create.rb

Satu lagi, biar kodenya lebih intention revealing, kita buat facade untuk kelas-kelas service. Jadi instead of manggilnya

Kita bikin supaya dipanggil dengan PremiumService.create_subscription(current_user, package). Caranya buat file dengan nama premium_service.rb yang letaknya langsung di folder app/services.

Di file ini juga kita deklarasi custom exception yang mungkin terjadi di service-service yang kita buat. Lihat ada parameter *args? Coba baca tulisan saya yang ini untuk memahami itu apa.

Jika nanti di kemudian waktu didapati kita membuat kelas service baru yang terkait dengan premium service maka di facade ini jangan lupa kita buat juga method-nya.

Keuntungan lain membungkus business logic ke dalam service object adalah kita bisa melakukan validasi di situ. Jika ada sesuatu yang tidak valid, lempar exception biar ditangkap oleh layer di atasnya. Mengacu ke studi kasus yang saya berikan, exception InvalidPremiumPackage akan dilempar kalau paket premium tidak valid. Dari situ tugas layer di atasnya, di kasus ini adalah controller, wajib mengantisipasinya.

Kalau misalnya memang ada kasus validasi lain terhadap proses pembuatan subscription, tambahkan di service itu juga. Contoh, ketika user sudah menjadi premium member, pengeksekusian terhadap service ini akan kena exception dengan tipe UserAlreadyPremium

Tentunya jangan lupa untuk membuat kelas UserAlreadyPremium di premium_service.rb

Facebook Comments
 

Agung Setiawan

Agung Setiawan adalah software engineer di BukaLapak.com, penulis sekaligus pecinta sastra, dan pembaca buku

 
Halo, perkenalkan saya Agung Setiawan.
Saya Software Engineer di BukaLapak.
Simak pemikian saya soal dunia Software Engineering via Twitter di @agungsetiawanmu dan facebook
Blog ini saya update seminggu sekali jadi sering-sering saja mampir
Mau belajar Vim bareng saya?
Belajar ngoding dari nol menggunakan PHP

Leave a Reply

Your email address will not be published. Required fields are marked *