Bulan Kedua Fellowship: Don’t Overcomplicate Things…

Halo! Kali ini saya ingin menceritakan kegiatan fellowship IA TOKI pada bulan kedua.

Sebelumnya, ada beberapa alumni yang bertanya hal fundamental berikut ini:

Apa bedanya TOKI dengan IA TOKI?

Secara sederhana, TOKI merupakan “badan” bentukan pemerintah yang bertujuan untuk memberangkatkan 4 siswa pada ajang IOI setiap tahunnya. Untuk mewujudkan hal ini, TOKI menyelanggarakan berbagai macam kegiatan, seperti OSK, OSP, OSN, dan Pelatnas.

Sedangkan, IA TOKI (Ikatan Alumni TOKI) merupakan “badan” bentukan para alumni berbentuk asosiasi. Definisi alumni di sini adalah orang-orang yang pernah mengikuti Pelatnas TOKI dan, maupun yang tidak dengan pertimbangan khusus. Nah, salah satu tugas dari IA TOKI adalah membantu TOKI menyelenggarakan berbagai kegiatannya. Misalnya, IA TOKI dapat membantu Pelatnas TOKI dengan menyediakan server dan soal-soal.

Kegiatan IA TOKI tidak hanya terbatas membantu kegiatan-kegiatan resmi TOKI saja. Salah satu hal besar yang dilakukan saat ini adalah mengembangkan platform TOKI Learning Center versi terbaru, yakni yang saya dan Jordan lakukan pada fellowship setahun ini.

Bala Bantuan

Dalam pengerjaan proyek TOKI Learning Center baru, saya dan Jordan dibantu oleh Petra sebagai project manager dan Deri sebagai product owner. Keduanya tentu saja bukan full time IA TOKI karena masih menjabat sebagai CTO di tempat masing-masing (Petra di UrbanIndo dan Deri di Traveloka).

Untuk komunikasi satu sama lain, kami biasa bertemu dengan Deri kira-kira sebulan sekali di kantor Traveloka untuk berdiskusi hal-hal teknis seperti teknologi dan algoritma. Sedangkan, komunikasi dengan Petra dilakukan setiap weekend via Skype untuk berdiskusi jadwal pengerjaan.

Judgment Angels

Proyek TOKI Learning Center versi terbaru yang sedang kami kembangkan diberi codename Judgment Angels, atau disingkat Judgels. Proyek ini sebenarnya merupakan implementasi dari tugas akhir Jordan dengan topik “sistem autograder yang ekstensibel.” Secara singkat, kami memecah sebuah aplikasi TOKI Learning Center menjadi beberapa komponen, yakni:

  • Single sign-on. Nantinya kami ingin OSN, Pelatnas, ataupun lomba-lomba lokal dapat menggunakan satu akun yang terpadu.
  • Repositori soal. Kami ingin agar seluruh soal-soal TOKI dapat terpusat di suatu tempat sehingga dapat di-manage dengan baik. Secara pribadi, saya ingin agar repositori soal ini dapat mendukung tipe soal apapun, seperti soal-soal IOI beberapa tahun terakhir ini.
  • Sistem kompetisi. Kami ingin agar sistem ini mudah dideploy dan digunakan untuk OSN maupun lomba-lomba lokal.
  • Sistem training. Mirip seperti kompetisi, namun lebih ke arah untuk pelatihan seperti USACO atau TOKI Training Gate yang lama.

dan banyak komponen lainnya yang lebih bersifat teknis (seperti engine grader).

By the way, nama “Judgment Angels” merupakan ide dari Jordan dan benar-benar digunakan dalam tugas akhirnya. Komponen-komponen Judgels di atas pun diberi subcodename sendiri, yang masing-masing merupakan nama malaikat dalam mitologi Yunani, seperti Jophiel, Sandalphon, Raphael, dan lain-lain.

Kami mengembangkan Judgels menggunakan Play framework dengan bahasa Java. Alasan utamanya adalah terdapat dukungan multithreading yang mudah pada Java, sifat static typing pada bahasa Java sehingga mempermudah debugging, dan build system yang enak pada Play framework, yakni menggunakan SBT dan Typesafe Activator. Alasan lainnya adalah Jordan sudah pernah menggunakan framework yang mirip Play saat intern di Traveloka, dan saya sendiri juga menggunakan Java dengan ekstensif saat intern di Palantir.

CRUD Generator

Saya dan Jordan memiliki suatu kesamaan yakni sama-sama pernah menggunakan framework Yii. Pada Yii, terdapat fitur yang sangat berguna yaitu CRUD generator (bernama Gii). Dengan Gii, kita tinggal mendefinisikan model berupa tabel pada database, lalu source code untuk segala kelas yang berhubungan dengan CRUD pada model tersebut akan di-generate dan tinggal dipakai saja (atau setidaknya dimodifikasi).

Berhubung Judgels terdiri atas beberapa komponen dengan interface yang ingin dibuat mirip, kami mencoba mengimplementasikan hal yang serupa pada Play framework. Intinya adalah: kami tidak ingin ada duplikasi kode! Berbeda dengan Gii, kami tidak membuat generator source code, tetapi kami ingin membuat kelas model dan kelas controller dasar yang tinggal di-extends untuk menghasilkan fungsionalitas CRUD. Misalnya, ketika ingin membuat fitur CRUD pengguna, kami ingin agar kami tinggal membuat seperti ini:

public final class UserModel extends AbstractCrudModel {
    public long id;
    public String username;
    public String realName;
}

public final class UserController extends AbstractCrudController<UserModel> {
    // action methods
}

(catatan: kode di atas hanya “ilustrasi” saja.)

(catatan lain: pada Play framework, secara default semua method untuk action pada controller harus bersifat static. Karena kami ingin melakukan reuse dengan inheritance, maka kami menggunakan fitur Play agar controller bersifat seperti objek.)

Pada mulanya, pembuatan kelas-kelas CRUD ini berjalan dengan lancar dan kami yakin apa yang kami buat akan sangat berguna. Namun, semua berubah ketika kami mulai mencoba mengaplikasikannya pada beberapa komponen Judgels. Contoh nyatanya, untuk kelas User, kami ingin menambahkan field password. Tentu saja ketika form User ditampilkan, field password haruslah bertipe password (yakni, semua input diganti menjadi bintang-bintang/bulatan-bulatan). Bagaimana cara membedakan dengan field username, padahal tipenya sama-sama string?

Solusi kami adalah menggunakan annotation, kira-kira seperti ini:

public final class UserModel extends AbstractCrudModel {
    public long id;
    public String username;
    public String realName;

    @CrudFieldType(CrudFieldTypes.PASSWORD)
    public String password;
}

Kemudian permasalahan lain muncul. Bagaimana kalau ada field yang tidak ingin ditampilkan pada suatu tipe CRUD tertentu? Misalnya, kita tentu tidak ingin menampilkan password pada halaman daftar semua User. Solusi kami adalah menggunakan annotation lainnya, kira-kira seperti ini:

public final class UserModel extends AbstractCrudModel {
    public long id;
    public String username;
    public String realName;

    @CrudFieldType(CrudFieldTypes.PASSWORD)
    @CrudFieldVisible({CrudAction.CREATE, CrudAction.UPDATE, CrudAction.VIEW})
    public String password;
}

Kemudian muncul banyak lagi permasalahan seiring berjalannya waktu. Bagaimana kalau kita ingin ada tulisan tertentu di sebelah suatu field? Bagaimana kalau setelah create user, kita ingin redirect ke suatu halaman? Dan yang paling kompleks, bagaimana kalau kita ingin melakukan post-processing, seperti, melakukan hash pada password sebelum disimpan pada server?

Mulanya kami mencoba mendukung itu semua, dengan cara menambah annotation baru dan menambah method abstract yang dapat di-override kalau ingin terdapat semacam post-processing. Lama kelamaan, codebase kami menjadi semakin kompleks. Bahkan kami jadi seperti membuat framework sendiri :p Lama-kelamaan, kami mencapai suatu titik yang mana kami merasa ini semua terlalu rumit. Setelah merenung, dan juga berdiskusi dengan Petra, kami membuat suatu keputusan besar: kami membuang ide ini secara total.

Sebelum membuat keputusan ini, kami mencoba mencari artikel-artikel pendukung. Lalu saya menemukan sebuah artikel yang menyatakan filosofi dari sebuah controller (terutama pada Play):

  • Controller seharusnya sederhana, dan hanya me-route permintaan HTTP dari pengguna ke kelas lain.
  • Fungsionalitas tambahan dari sebuah method sebaiknya dicapai melalui komposisi method, bukan inheritance.

Ternyata kami melanggar keduanya: controller kami kompleks dan mengandalkan inheritance (bahkan controller kami bersifat generic!).

Ya, kami sudah menghapus banyak kelas yang berhubungan dengan fitur CRUD generator ini. Pada akhirnya kami menggunakan cara manual saja. Hasilnya? Koding jadi jauh lebih cepat, dan kodenya lebih mudah dibaca meskipun terdapat sedikit duplikasi di sana-sini.

Melalui hal ini kami menarik beberapa pelajaran. Yang paling utama adalah don’t overcomplicate things, terutama pada awal-awal pengembangan. Yang berikutnya adalah terdapat trade-off antara adanya duplikasi kode dan rumitnya kode karena terlalu banyak hal generic yang harus diparameterisasi (seperti kasus model di atas). Pada banyak kasus kita sebaiknya memilih adanya sedikit duplikasi kode namun kodenya jadi lebih bersih.

Mungkin beberapa minggu kami berlalu sia-sia karena digunakan untuk menulis kode yang sama-sekali tidak digunakan. Namun, pelajaran kami dapatkan cukup berharga. Pelajaran ini sangat mempengaruhi salah satu pengembangan selanjutnya yaitu untuk komponen repositori soal. Kami ingin repositori mendukung pembuatan sebanyak mungkin tipe soal, dari ICPC-style sampai IOI-style. Jika ingin benar-benar reusable dengan tanpa duplikasi, maka kami harus mencari persamaan-persamaan antara berbagai tipe soal lalu menentukan parameter-parameter yang harus dikustomisasi. Kami hampir melakukan hal ini, lalu kami teringat akan kegagalan kami di CRUD generator. Pada akhirnya kami memikirkan ulang solusinya dan sebisa mungkin mengimplementasikan solusi yang tidak rumit.

Deployment

Kami pun mulai mencoba deploy komponen-komponen yang sedang dikembangkan pada suatu deployment server. Namun kami belum bisa share kepada publik, dengan alasan:

  • Komponen-komponennya memang belum terlalu siap untuk diuji coba.
  • Kami menggunakan hosting AWS free tier. Saat kami men-deploy banyak komponen sekaligus, karena masing-masing merupakan aplikasi Play yang memiliki web server sendiri, server AWS gratisannya tidak cukup kuat (RAM hanya 1 GB!) dan crash. Solusinya adalah kami berencana mencoba hosting berbayar di suatu tempat lain.

Code Review

Terdapat setidaknya dua jenis code review yang kami ketahui:

  • Review, yaitu melakukan code review sebelum kode di-push.
  • Audit, yaitu melakukan code review setelah kode di-push.

Pada mulanya, kami menggunakan tipe pertama. Bahkan, pada awal-awal kami benar-benar “relijius” dalam menjalankannya, yakni semua kode yang ditulis harus benar-benar diperiksa oleh yang lain dulu sebelum di-push. Lama-kelamaan, kami merasa hal ini cukup menghambat produktivitas dan pengembangan fitur. Akhirnya, kami beralih menggunakan tipe audit: kami akan mengalokasikan slot waktu khusus untuk review dan refactor jika diperlukan. Hal ini rupanya cukup efektif.

Yak, begitulah update di bulan kedua. Stay tuned!

3 thoughts on “Bulan Kedua Fellowship: Don’t Overcomplicate Things…

  1. Wah keren sekali
    Apakah toki learning kedepanya akan ada fitur untuk membuat contest yang terbuka untuk umum?
    menurut saya fitur tersebut akan sangat berguna untuk edukasi siswa terutama pelatihan pada daerah-daerah, sehingga peserta pada daerah-daerah juga mampu bersaing di ajang OSN, karena sangat sulit bagi guru-guru untuk membuat contest untuk latihan murid-muridnya
    Terimakasih,

    1. Dan pertanyaan Tommy Budiman belum dijawab :v…
      Ok… aku bukan bagian dari developer TLC next gen… but dapet2 gossip kalau ini memang rencananya bisa untuk di gunakan di daerah2 untuk ajang latihan lokal seh :-?… tapi data siswanya tetap terpusat (karena single Log-in tadi), dan soal2 atau kontes yang dibuat itu bisa dibuat private, sehingga bagi yang berkepentingan saja yang bisa melihat… :-?…

      Tapi… well tunggu klarifikasi dari Ashar atau Jordan saja 😀

Leave a Reply to Ashar Fuadi Cancel reply