Mengatasi Isu Cross-Origin Resource Sharing (CORS)

Ceritanya kemarin saya sedang mengembangkan sebuah aplikasi web bersama teman-teman seangkatan saya. Saya kebagian in charge di tim back end. Saat itu saya sedang mengerjakan halaman “Tentang Kami” yang berisi profil-profil anggota tim pengembang.

Aplikasi ini dikembangkan dengan menggunakan WordPress. Kebetulan, profil user di WordPress ditangani oleh Globally Recognized Avatars (Gravatar) yang berarti tentunya, detail profil user yang ada seperti foto, facebook, twitter dan lainnya harus di-fetch dari situs Gravatar tersebut.

Syukurnya, Gravatar punya API yang dapat digunakan oleh publik. Jadi saya gunakan saja API tersebut untuk mengambil data.

about-us-page

Tampilan halaman “Tentang Kami” yang sedang dikerjakan.

Sebagai informasi, jumlah tim kami ada 11 orang, dengan kata lain saya harus melakukan perulangan 11 kali untuk mengambil data profil dari situs tersebut. Belum lagi untuk menampilkan profil kontributor yang nanti jumlahnya bisa banyak. Pengambilan data akan dilakukan dengan menggunakan PHP biasa. Jadi, implementasinya waktu itu seperti ini:

foreach ($users as $user) {
    $str = file_get_contents( 'http://www.gravatar.com/' . md5($user->user_email) . '.php' );
    $profile = unserialize( $str );
    if ( is_array( $profile ) && isset( $profile['entry'] ) )
        /* Action to display profile... */
}

Saat dicoba, ternyata proses loading-nya lama sekali. -_- Saya baru sadar, proses pengambilan data oleh PHP dilakukan secara berurut. Dengan kata lain, profil si user akan diambil satu-satu, dan prosesnya harus ditunggu sampai selesai baru bisa mengambil profil lainnya. Kalau misalnya ada masalah di koneksi pada saat melakukan fetching salah satu profile, tentu saja semuanya jadi ikut bermasalah. Belum lagi kalau misalnya nanti jumlah user yang ada menjadi lebih banyak seiring berjalannya waktu. Mau berapa lama loading-nya?

Karena itu, supaya aman, proses fetching informasi profile dari Gravatar harus dilakukan secara paralel. Masalahnya, PHP tidak mendukung multithread secara default. Jadi, bagaimana?

Tentu saja, JavaScript!

Dengan menggunakan jQuery, profilnya akan diambil secara asynchronous, jadi tampilan halaman akan muncul terlebih dahulu, baru kemudian profilnya akan di-append satu-satu ke halaman tersebut. Untungnya Gravatar menyediakan API yang dapat digunakan untuk mengambil data dalam format JSON. Kodenya jadi begini:

$(document).ready(function() {
    $.get('http://www.gravatar.com/' + userMd5Hash + '.json', function(data) {
        /* Operation to parse JSON (emitted). */
        $("#" + userMd5Hash + "-accounts").append(/* ... */);
    });
});

Saat dicoba dijalankan, tiba-tiba saya mendapatkan pesan error di jendela console. Tampilannya mirip seperti di bawah ini:

cors-error

Nah, ada apa lagi ini? -_-

Ternyata, operasi GET menggunakan AJAX dengan menggunakan jQuery yang saya lakukan terbentur oleh same origin policy. Ini ada apa lagi ya? o.O

Ternyata..

Jadi, saya mengerjakan halaman ini di localhost, sedangkan profil yang ingin saya ambil, ada di alamat domain gravatar.com yang tentunya berbeda lokasinya. Secara defaultweb browser tidak mengizinkan langsung operasi pengambilan data yang berbeda domain seperti ini untuk alasan keamanan.

Setelah googling beberapa saat, ternyata untuk mengatasinya, harus dilakukan penyetelan yang memungkinkan untuk melakukan Cross-Origin Resource Sharing (CORS). Untuk melakukannya, ada 2 pilihan yang dapat dilakukan:

Enable CORS di Server Tujuan

Untuk dapat melakukan CORS, pemilik server harus menambahkan header khusus di setiap response yang dikembalikan dari tiap request yang diberikan yaitu:

Access-Control-Allow-Origin: *

Jika header ini tidak didapatkan di response yang dikirimkan balik, maka browser akan memberikan pesan error seperti yang ada di atas tadi.

API di website lain seperti GitHub misalnya, sudah mengizinkan CORS secara default (lihat gambar di bawah, dan perhatikan kotak merah):

github-response-header

Sedangkan, Gravatar tidak mengizinkannya (lihat gambar di bawah):

gravatar-response-header

Karena saya tidak mungkin mengotak-atik API server milik Gravatar, ya apa boleh buat. -_- Tapi untungnya, di sisi client ada hal lain yang dapat dilakukan, yaitu:

Gunakan JSON with padding (JSONP)

Teknik yang dapat dilakukan untuk mengatasi ini adalah menggunakan JSONP. Implementasinya, cukup dengan mengganti rutin jQuery yang digunakan, dan mengubah URL request dengan menambahkan parameter callback.

$(document).ready(function() {
    $.getJSON('http://www.gravatar.com/' + userMd5Hash + '.json?callback=?', function(data) {
        /* Operation to parse JSON (emitted). */
        $("#" + userMd5Hash + "-accounts").append(/* ... */);
    });
});

Fiuh, dan akhirnya berhasil juga. 😀

Syukur sekali saya mendapatkan masalah ini. Kebetulan, aplikasi yang sedang saya kerjakan dan skripsi saya saat ini banyak berhubungan dengan RESTful API, dan isu seperti CORS seperti ini pasti akan sangat membingungkan nanti untuk orang yang menggunakan API yang saya kembangkan. Jadi, untuk pengembang REST API, sepertinya isu CORS seperti ini patut untuk diperhatikan.

Demikian cerita ini, mudah-mudahan bermanfaat untuk pembaca ya. 🙂

Pentingnya Modularisasi Dalam Pemrograman

Don’t Repeat Yourself (DRY). Pernah mendengar slogan ini? DRY merupakan sebuah prinsip pengembangan software yang makna utamanya adalah mengurangi repetisi semaksimal mungkin.

Mungkin repetisi yang pembaca lakukan tidak akan terlalu terasa kalau pembaca menulis software yang pendek (seperti tugas algoritma dan pemrograman di kelas misalnya). Kalau urusannya dengan software siap pakai beneran, barulah semuanya terasa. -_-

Contoh singkat, pernah menulis program dengan Java? Untuk mengeksekusi 1 query ke database MySQL saja misalnya, paling tidak harus ada kode seperti di bawah ini bukan?

import java.sql.*;

import javax.swing.JOptionPane;

public class MySQLSampleProgram {

    public static final String  DB_NAME     = "dbname";
    public static final String  DB_HOST     = "localhost";
    public static final int     DB_PORT     = 3306;
    public static final String  DB_USER     = "dbuser";
    public static final String  DB_PASSWORD = "dbpassword";

    public static Connection conn = null;
    public static Statement stat = null;

    public static void main(String[] args) {
        try {
            Class.forName("com.mysql.jdbc.Driver");
            conn = DriverManager.getConnection("jdbc:mysql://" + DB_HOST + ":" + String.valueOf(DB_PORT) + "/" + DB_NAME, DB_USER, DB_PASSWORD);
            stat = conn.createStatement();

            String query = "SELECT * FROM table;";

            ResultSet rs = stat.executeQuery(query);

            /* Continued... */
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
        }
    }
}

Baru setelah melakukan eksekusi terhadap query, hasil yang didapatkan dari database bisa dipakai. Bayangkan kalau setiap form yang pembaca buat harus mencantumkan kode konfigurasi database di atas (DB_NAME dan seterusnya) dan kode yang ada di blok try di atas (Class.forName dan seterusnya). Fiuh, capek bukan?

Untuk itulah pentingnya modularisasi. Dengan mengelompokkan operasi-operasi yang sering dilakukan ke dalam suatu modul (function, procedure atau class), maka jika dibutuhkan, operasi-operasi tersebut tinggal dipanggil dengan cara yang singkat. Di sinilah pemrograman berorientasi objek menjadi menyenangkan. 😉

Dengan menganggap masalah yang hendak diproses sebagai objek, maka proses pemecahan masalah dapat dilakukan langsung tanpa harus melaksanakan serentetan operasi yang berulang-ulang. Untuk menyelesaikan contoh kasus koneksi database di Java seperti di atas misalnya, saya melakukan modularisasi dengan cara menulis class yang dapat digunakan untuk menyederhanakan eksekusi query. Coba lihat di sini: https://gist.github.com/imamhidayat92/5418582

Kalau pembaca menggunakan class yang saya tulis tersebut, mengeksekusi query hanya akan sekedar memanggil perintah sederhana seperti berikut:

import helper.MySQLConnector;

import java.sql.*;

import javax.swing.JOptionPane;

public class MySQLSampleProgram {

    public static void main(String[] args) {
        try {
            String query = "SELECT * FROM table;";

            ResultSet rs = MySQLConnector.executeQuery(query);

            /* Continued... */
        } catch (Exception e) {
            JOptionPane.showMessageDialog(null, e.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
        }
    }
}

Hemat bukan jadinya? 😛

Melakukan sesuatu yang repetitif itu akan sangat melelahkan. Tanpa modularisasi, proses meng-update kode juga akan menjadi rumit. Bayangkan, ada berapa kode serupa yang harus diperbaiki kalau ternyata ada prosedur yang salah?

Dengan modularisasi, tentu saja menulis program juga akan menjadi lebih efisien, dan kodenya akan lebih mudah dibaca.

Semoga bermanfaat. 😉

Bersiap untuk Menjadi Seorang Ph. D. di Bidang Computer Science

Siang tadi, saya mengikuti seminar tentang mempersiapkan diri menjadi Ph. D. students yang diselenggarakan di Surya University. Pagi-pagi saya sudah bangun untuk langsung menuju ke Tangerang. Dengan sangat terpaksa saya juga membolos mata kuliah Komputer dan Masyarakat pagi ini. Mudah-mudahan ini bolos yang terakhir untuk semester ini.

Setelah sempat nyasar dan pindah angkot sampai lebih dari 5 kali, alhamdulillah saya sampai juga. 😀 Surya University gedungnya masih dalam tahap pembangunan. Jalan untuk menuju ke gedung utamanya saja masih berbatu-batu. Penasaran, seperti apa nanti jadinya universitas ini. Sebelum sampai di Surya University, saya sempat nyasar ke STKIP Surya yang terletak di depan Universitas Multimedia Nusantara (UMN). Gedung STKIP ada persis di depan UMN itu, sedangkan gedung Surya University ternyata ada di belakangnya.

Pembicaranya adalah Bapak Haryadi Gunawi, beliau adalah profesor di University of Chicago. Peserta yang datang tidak banyak, tapi itu justru keuntungan untuk kami karena diskusi menjadi informal, yang dengan kata lain, tentu saja lebih intim. Saya mendapatkan informasi tentang seminar ini dari facebook-nya Bapak Yohannes Surya dan segera langsung mendaftar online saat itu.

Selesai dari sana, yang saya rasakan adalah: khawatir, dan ada rasa sedikit menyesal juga. “Don’t start too late,” begitu kata Pak Haryadi. Menurut beliau, untuk mempersiapkan diri menjadi Ph. D. students, tentunya harus mempersiapkan diri dengan sangat matang, mulai dari memilih topik research yang tepat hingga mempersiapkan prerequisites-nya seperti GRE dan lainnya jika mau melakukan studi di luar negeri.

Jadi strategi yang beliau sampaikan kurang lebih begini:

Pada tahun ke-1 dan 2 pilihlah topik yang kita sukai. Jangan lupa, ambil pula course yang berkaitan dengan system. Saya agak bingung juga soal ini, karena seperti apa system course lupa saya tanya tadi. -_- Tapi intinya, ambillah mata kuliah yang fundamental dan berhubungan dengan topik yang kita sukai. Namun sepertinya metode ini tidak selalu bisa dipakai, karena ada beberapa universitas yang memang sudah memasang paket tiap semester untuk mahasiswanya.

Tahun ke-3, mulailah undergraduate research. Berdasarkan topik yang kita pilih, mulai lakukan research.

Tahun ke-4, bersiaplah untuk GRE, dan siap-siap untuk menjadi kandidat Ph. D.

Saya pernah dengar kalau di luar negeri, kalau ada mahasiswa yang research-nya memang sudah bagus, maka sang mahasiswa boleh loncat, dari S1 langsung ke S3, dan ternyata memang benar. Namun jika ternyata secara akademis sang mahasiswa belum memiliki pengalaman research yang mumpuni, bisa menjembataninya dengan mengambil S2 terlebih dahulu.

Lalu beliau juga mengatakan, untuk melakukan research, paling tidak butuh waktu 2 tahun. Dalam melakukan research yang berkaitan dengan suatu sistem komputer, butuh 3 fase yaitu: understandre-design dan evaluate. Untuk memahami suatu sistem butuh waktu, dan tentunya saat melakukan research, peneliti pasti akan memodifikasi desain yang sudah ada sebelumnya untuk menemukan sesuatu yang baru. Untuk itulah 2 tahun tersebut diperlukan.

Nah, ada tips dari beliau tadi untuk yang mau bersiap-siap.

Pertama, pilih topik yang mau kita tekuni dengan benar. Topik industri berbeda dengan topik untuk penelitian. Web development atau iPhone apps development misalnya, itu adalah topik industri. Topik penelitian biasanya lebih dalam, bukan dari sisi aplikatif.

Kedua, pilih fakultas yang memang mendukung untuk melakukan research. Beliau bercerita tadi, dalam melakukan research butuh koneksi dan relasi juga. Jadi saat memilih tempat untuk melakukan research, biasanya kita akan mencari universitasnya dulu, baru kemudian melihat fakultasnya. No, kata beliau seharusnya tidak seperti itu. Tentukan dulu fakultasnya, bahkan tentukan dulu nama orangnya malahan. Orang yang dimaksud tentu saja profesor-profesor yang sudah mumpuni di bidang yang mau kita tekuni. Tujuannya adalah supaya nanti ketika penelitian kita sudah selesai, pak profesor bisa memberikan kita recommendation letter yang akan sangat berguna untuk mendapatkan gelar Ph. D. tersebut.

Ketiga, carilah paling tidak 5 konferensi internasional yang membahas topik yang kita tekuni. Dari sana nanti, tentukan keywords yang akan membantu kita untuk menemukan pembahasan yang tepat dan bisa jadi sedang trend. Lalu rajin-rajin baca paper-nya. Tidak harus semuanya, abstraknya saja cukup. Dari sana nanti kita akan menambah pengetahuan tentang topik yang mau kita teliti. Selain itu, dengan mengetahui konferensi-konferensi tersebut, kita juga jadi tahu, universitas mana saja yang aktif dalam topik yang kita sukai. Data ini tentu saja bisa kita gunakan untuk memilih di mana nantinya kita akan mengambil studi.

Keempat, tidak perlu harus menjadi author dari sebuah research. Jadi co-author saja itu sudah cukup. Memulai research sendiri dari awal itu bukan hal yang mudah. Jadi kalau ternyata sedang ada research yang sedang berlangsung dan berkaitan dengan topik yang kita sukai, ambil saja. Berkomitmenlah untuk menyelesaikan research itu, dan itu akan membantu juga nanti untuk mendapatkan Ph. D.

Oh iya, yang paling jleb dari beliau adalah yang ini: soal karakter. Menurut beliau, butuh 3 karakter untuk menyelesaikan Ph. D. dan karakter inilah justru yang paling penting dan akan sangat menentukan. Ketiga karakter itu adalah: consistent, persistent, dan independent.

Consistent, artinya seorang researcher harus berkomitmen terhadap hal yang sedang ia teliti. Sediakan waktu yang cukup. Masalahnya adalah, research memang butuh komitmen dan pengorbanan besar. Sebagian besar research itu lazimnya dilakukan secara voluntarily, alias unpaid. Jadi memang harus konsisten, karena kalau tidak konsisten, bagaimana research-nya mau selesai?

Persistent artinya kita teliti dan cermat dalam melakukan research. Jangan sampai hasil yang ditemukan dari research ternyata salah-salah, entah karena metodenya, atau karena interpretasinya. Dalam melakukan research kita harus berusaha menghasilkan sesuatu yang benar dan terbaik.

Independent, artinya kita harus mandiri saat melakukan research. Hihi, kata beliau sering-seringlah bersahabat dengan Google. 😀 Saat seorang peneliti menemukan masalah, kepada siapa dia harus bertanya? Research question itu adalah pertanyaan yang hasilnya bahkan belum pernah ditemukan siapapun. Si peneliti itulah yang harus menjawab pertanyaan yang ia buat sendiri, dan jawaban dari pertanyaan itu belum ada. Jadi, kalau saat menemukan kendala sedikit lalu si peneliti ‘cengeng’ dalam mencari solusinya, pasti akan sulit untuk menyelesaikan penelitian. Jadi, tiap punya kendala (biasanya kendala teknis), googling! Jangan mengeluh ke orang lain. 😉

Tanpa 3 karakter ini, akan sulit mau menjadi seorang Ph. D.

Fiuh, berat bukan? 😐

Tadi di akhir pertemuan, beliau sempat membahas beberapa topik yang menarik untuk dijadikan research. Diantaranya adalah tentang Big Data dan Cloud Computing. Kebetulan kemarin saya mengambil course tentang Web Intelligence and Big Data di Coursera, jadi lumayan nyambung tadi mendengar penjelasan beliau, hehe. Coba saja cari, ada banyak kata kunci yang menarik untuk kita ketahui, di antaranya: map reduce, software-defined networkinghadoopscale outdata center programming, stragglers. Ayo, googling. 😛

Begitulah kira-kira ringkasan seminar yang saya hadiri hari ini. Saya dulu pernah memasang misi untuk dijalankan persis sebelum saya kuliah di Paramadina, yaitu: sebelum tahun 2025, saya sudah menyelesaikan doctoral degree. Kalau ada pembaca yang ikhlas dan berbaik hati, doakan saya ya. 🙂

Semoga bermanfaat.

Iseng di Kelas Praktikum Algoritma dan Pemrograman

Semester lalu alhamdulillah saya diberi kepercayaan oleh dosen mata kuliah Algoritma & Pemrograman di kampus saya (Bapak Harry T. Y. Achsan) untuk jadi asisten. Senang sekali tentunya, karena mata kuliah ini adalah mata kuliah favorit saya. 😉

Ngomong-ngomong, mengajar di kelas itu sangat menyenangkan sebenarnya. Hal yang membuatnya jadi agak kurang menyenangkan adalah kewajiban di akhir untuk memberikan penilaian. Selain sulit dan ribet, kadang-kadang agak khawatir juga bahwa terjadi subjektifitas dalam penilaian saya.

Karena itu kemarin waktu melakukan asistensi saya sempat membuat UTS yang penilaiannya otomatis berdasarkan jumlah soal yang berhasil diselesaikan.

Namun tentunya, melakukan hal ini butuh pengorbanan yang lain juga. Saya harus menciptakan sejenis grader yang akan melakukan pengujian input dan output yang nantinya kemudian akan menilai hasil pekerjaan peserta kelas saya.

Dengan meluangkan waktu sejenak, akhirnya saya membuatnya juga. Ini tampilannya:

Tampilan Score Board UTS Algoritma dan Pemrograman

Tampilan Score Board UTS Algoritma dan Pemrograman

Kalau dipikir-pikir, jatuhnya sama seperti kontes pemrograman. 😛

Sebenarnya, kalau fasilitasnya mendukung, saya tidak perlu capek-capek melakukan pembuatan aplikasinya, karena sudah banyak programming contest management system yang sudah mumpuni seperti PC^2 atau DOMjudge. Kendalanya, saya tidak punya server sendiri, sehingga saya menggunakan cara lain untuk melakukan penilaian.

Oh iya, soal yang saya buat bisa di-download di sini.

Kelas pemrograman ini menggunakan bahasa pemrograman Java. Jadi, untuk melakukan penilaian, saya membuat sebuah library yang disimpan dalam format JAR yang kemudian dapat digunakan untuk melakukan penilaian sekaligus untuk men-submit nilai ke server. Server yang saya maksud bukan server beneran sih. Saya menaruh score board tadi di website yang saya miliki di alamat http://muslihat.net.

Library yang saya implementasikan sebenarnya sederhana. Seluruh input dan output yang benar untuk setiap testcase yang diujikan ke program buatan peserta diletakkan di dalam array. Karena saya tidak mungkin menganalisis output yang dihasilkan program peserta (berhubung saya tidak bisa sekonyong-konyong mengubah hosting server menjadi grader server), maka setiap soal yang saya buat merupakan soal OOP yang tiap method-nya tinggal di-override saja.

Hasilnya lumayan juga ternyata. Saya jadi tidak perlu capek menilai pekerjaan mahasiswa peserta praktikum. Cukup santai saja melihat scoreboard. Hihi.

Barangkali, seharusnya mata kuliah algoritma dan pemrograman diubah modelnya menjadi seperti ini saja. Selain lebih fun, hal ini mempermudah dosen juga.

Bayangkan kalau seorang dosen memberikan tugas pemrograman. Setelah men-download source code dari masing-masing muridnya, sang dosen harus melakukan compile dan kemudian menguji input dan output dari program tersebut. Selain melelahkan, kadang-kadang jadi kurang teliti. Akan lebih baik kalau ada proses yang terautomatisasi untuk melakukan hal tersebut.

Nantinya kalau sang murid mau yang lebih serius, ada banyak kompetisi pemrograman yang model pengujiannya juga seperti ini. Buat programnya, submit untuk dinilai, dan kemudian lihat hasilnya. Kompetisi seperti International Collegiate Programming Contest (ICPC) menggunakan model seperti ini. Kompetisi yang berskala nasional seperti COMPFEST dari UI atau ITB-PC juga menggunakan model yang seperti ini.

Bayangkan, dari yang sekedar iseng-iseng mencoba kode, bisa sekalian keliling dunia kalau berhasil. Kenapa tidak? 😉

Menghitung Pemangkatan Bilangan Dengan Algoritma Divide and Conquer

Secara naif, untuk menghitung pemangkatan bilangan pangkat n, kita akan membutuhkan tepat n kali operasi perkalian dengan bilangan (a dikali dikali dan seterusnya sebanyak kali). Hal ini tentu saja kurang efisien karena jika nilainya besar, algoritma dengan kompleksitas O(n) relatif lambat.

Untuk mengatasi hal ini, dapat digunakan metode rekursif divide and conquer untuk melakukan pemangkatan bilangan yang performanya jauh lebih cepat, yaitu O(log n).

int pow(int a, int n) {
    if (n == 0) return 1;

    int x = pow(a, n/2);

    if (n % 2 == 0) {
        return pow(x, 2);
    }
    else {
        return a * pow(x, 2);
    }
}

Algoritma ini berangkat dari ide, bahwa operasi pangkat n itu sama saja dengan melakukan operasi kuadrat dari pangkat (n / 2) yang dilakukan secara rekursif.

Jadi, kalau ada yang lebih cepat, kenapa tidak? 😉