Category Archives: teknis

Membuat Bot Telegram

Messenger telegram masih kurang populer di Indonesia, padahal Telegram memiliki banyak kelebihan dibanding messenger lain, misalnya: lebih cepat, bisa diakses via web, sinkronisasi pesan, dsb. Salah satu fitur yang baru diperkenalkan oleh Telegram adalah bot. Bot adalah software yang secara otomatis merespon pesan yang kita berikan.

Setelah saya membuat bot Bot Alkitab, beberapa orang bertanya bagaimana caranya membuat bot. Dengan harapan Telegram jadi lebih populer, saya tuliskan di sini dasar pembuatan bot.

Sebelum membaca Artikel ini, silakan baca dulu artikel dari telegram yang memperkenalkan soal bot, lalu bereksperimen lah dengan bot-bot yang sudah ada, supaya bisa mengerti fitur bot dan interaksi dengan bot:

https://telegram.org/blog/bot-revolution

Mendaftarkan Bot

Sekarang setelah siap membuat bot, langkah pertama adalah mendaftarkan nama bot kita. Ini dilakukan dengan menggunakan BotFather.

Perintah yang perlu digunakan adalah /newbot. Perlu diperhatikan bahwa semua bot harus memiliki akhiran “Bot”. Setelah selesai, kita akan mendapatkan token, semacam ini: 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11. Token ini tidak boleh disebar (karena orang lain bisa mengambil alih bot Anda).

botfather

Setelah didaftarkan, kita bisa langsung menambahkan bot di daftar teman kita.

daftar-teman

Ketika mulai chat, ada tombol “Start”

tombol-start

Jika kita tekan itu, yang terjadi adalah kita mengirimkan perintah “/start” ke bot (semua perintah bot dimulai dengan “/”).

pesan-pertama

Tapi kita belum menulis kode untuk bot kita, jadi bot kita belum bisa membalas apapun.

Menerima Pesan

Bot bisa menerima pesan dengan dua cara: polling dan webhook.

Polling artinya kita yang akan meminta pesan ke server telegram. Kira-kira begini: eh ada nggak pesan buat bot saya, kalo nggak ada, bilang aja nggak ada setelah N detik ya. Kalau dalam N detik ada pesan masuk, langsung berikan ke saya pesannya.

Cara kedua adalah dengan webhook. Kira-kira begini: ini saya punya URL, kalau ada pesan masuk, segera posting ke URL ini ya, nanti saya proses. URL ini harus HTTPS.

Telegram hanya mau mengantarkan pesan dengan salah satu cara di atas, tidak bisa keduanya, defaultnya adalah cara pertama.

Cara pertama cocok jika server dijalankan secara internal. Misalnya jika dijalankan di raspberry pi di rumah. Kita tidak perlu IP publik, tidak perlu punya domain, tidak perlu setup HTTPS, dsb. Cara ini agak sedikit lebih lambat dari cara kedua jika penggunanya banyak.

Cara kedua cocok jika Anda sudah punya web server eksternal dan sudah punya HTTPS, atau memakai layanan yang sudah memakai HTTPS (contohnya Google App Engine).

Pertama saya bahas cara polling karena ini sangat praktis ketika development. Pertama kita coba akses pesan yang diterima bot. Kita bisa meminta menggunakan browser seperti ini:


https://api.telegram.org/botTOKEN/getUpdates

Contohnya seperti ini:

getupdates

Sebenarnya ada beberapa parameter ekstra yang bisa kita tambahkan. Pertama adalah timeout: menyatakan berapa lama kita akan menunggu sampai ada pesan. Kedua adalah limit yang menyatakan berapa pesan yang ingin kita terima (max 100). Dan ketiga yang penting adalah offset.

Jika Anda coba refresh URL sebelumnya (tanpa memberikan offset), maka telegram tidak tahu apakah Anda sudah memproses pesan itu atau tidak (batasnya 24 jam). Untuk memberi tahu telegram bahwa pesan tadi sudah kita baca, kita perlu memberikan offset berupa update_id terakhir plus 1, jadi untuk mendapatkan pesan-pesan setelah pesan di atas, saya bisa menambahkan offset seperti ini (sekalian saya berikan contoh memberikan timeout dan limit):


https://api.telegram.org/botTOKEN/getUpdates?offset=142757037&timeout=2&limit=1

Hasil kembalian getUpdates seperti ini:

{
 "ok":true,
 "result":[
 {
 "update_id":142757036,
 "message":{
 "message_id":3,
 "from":{
 "id":24912310,
 "first_name":"Yohanes",
 "last_name":"Nugroho",
 "username":"yohanesn"
 },
 "chat":{
 "id":24912310,
 "first_name":"Yohanes",
 "last_name":"Nugroho",
 "username":"yohanesn"
 },
 "date":1436950746,
 "text":"\/start"
 }
 }
 ]
}

Isi “result” adalah array of message (ada berbagai jenis message, bisa teks, video, dokumen, dsb, tapi dalam tutorial ini yang akan saya tangani hanya yang berisi “text”. Anda bisa membaca API Telegram untuk menangani jenis pesan yang lain.

Untuk membalas pesan, kita bisa menggunakan sendMessage. Anda bisa mencoba di browser (menggunakan token Anda) seperti ini (lihat chat_id di JSON di atas):


https://api.telegram.org/botTOKEN/sendMessage?chat_id=24912310&text=hello

Jika kita ingin menampilkan pesan sebagai balasan dari message tertentu, kita bisa menambahkan reply_to_message_id. Misalnya di atas tercantum message_id adalah 3:


https://api.telegram.org/botTOKEN/sendMessage?chat_id=24912310&text=hello&message_id=3

Jika kita menggunakan Python, kita bisa mendapatkan pesan updatenya dengan library requests (urllib juga bisa, tapi requests lebih enak). Karena URL requestnya sama semua prefixnya, saya membuat fungsi request_url untuk mempersingkat. Berikutnya agar singkat, saya hanya akan membahas PHP saja (dan Anda tetap bisa dengan mudah menerjemahkan ke Python).

def request_url(method):
    return  "https://api.telegram.org/bot"+TOKEN+"/" + method

def getUpdates(offset, limit=100, timeout=100):
    r = requests.get(request_url("getUpdates"),
                     params={"offset":offset,
                      "limit": limit,
                      "timeout": timeout
                      } )
    #asumsi semuanya OK
    result = r.json()
    if result["ok"]:
        return result["result"]
    return []

Kode yang sama di PHP:

<?php

include("token.php");

function request_url($method)
{
	global $TOKEN;
	return "https://api.telegram.org/bot" . $TOKEN . "/". $method;
}

function get_updates() 
{
        $resp = file_get_contents(request_url("getUpdates"));
        $update = json_decode($resp, true);
         
?>

Kerangka sebuah program PHP command line (metode polling) yang menangani pesan adalah seperti ini:

<?php
include("token.php");

function request_url($method)
{
	global $TOKEN;
	return "https://api.telegram.org/bot" . $TOKEN . "/". $method;
}

function get_updates($offset) 
{
	$url = request_url("getUpdates")."?offset=".$offset;
        $resp = file_get_contents($url);
        $result = json_decode($resp, true);
        if ($result["ok"]==1)
            return $result["result"];
        return array();
}

function send_reply($chatid, $msgid, $text)
{
    $data = array(
        'chat_id' => $chatid,
        'text'  => $text,
        'reply_to_message_id' => $msgid

    );
    // use key 'http' even if you send the request to https://...
    $options = array(
    	'http' => array(
        	'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
        	'method'  => 'POST',
        	'content' => http_build_query($data),
    	),
    );
    $context  = stream_context_create($options);

    $result = file_get_contents(request_url('sendMessage'), false, $context);
    print_r($result);
}

function create_response($text)
{
   return "definisi " . $text;
}


function process_message($message)
{
    $updateid = $message["update_id"];
    $message_data = $message["message"];
    if (isset($message_data["text"])) {
	$chatid = $message_data["chat"]["id"];
        $message_id = $message_data["message_id"];
        $text = $message_data["text"];
        $response = create_response($text);
        send_reply($chatid, $message_id, $response);
    }
    return $updateid;
}


function process_one()
{
	$update_id  = 0;

	if (file_exists("last_update_id")) {
		$update_id = (int)file_get_contents("last_update_id");
	}

	$updates = get_updates($update_id);

	foreach ($updates as $message)
	{
     		$update_id = process_message($message);
	}
	file_put_contents("last_update_id", $update_id + 1);

}

while (true) {
	process_one();
}
          
?>

Anda bisa mengakses sourcenya di sini:

https://gist.github.com/yohanes/987e1d48cbca9fde9377

Perhatikan bahwa ini perlu dijalankan di command line seperit ini:

$ php telegram-poll.php

Dan selama program masih berjalan, maka pesan yang masuk akan dibalas. Jika dijalankan di web server, maka akan timeout setelah beberapa detik/menit.

Isi file token.php hanyalah seperti ini:

<?php
$TOKEN="TOKENANDA";
?>;

Untuk metode webHook, perbedaannya hanya pada fungsi get_updates, dan process_one tidak diperlukan, loop while juga tidak diperlukan, karena pesan akan dikirim satu per satu dengan POST. Kita cukup membaca POST yang masuk (dengan membaca php//:input), dan mendecode JSON-nya.

<?php
//bagian awal sama dengan sebelumnya

$entityBody = file_get_contents('php://input');
$message = json_decode($entityBody, true);
process_message($message);

?>

Source lengkap di:

https://gist.github.com/yohanes/3181a5424d10ea5e2429

Untuk menggunakan methode webHook, Anda harus melakukan beberapa hal:

  1. Mempersiapkan URL HTTPS
  2. Menset urlWebhook

Untuk bagian pertama: Anda perlu memiliki hosting yang mendukung HTTPS, Anda juga bisa memakai layanan cloudflare.com yang otomatis membungkus web Anda dengan https. Berikutya kita perlu mensetup web hook. Contohnya jika URL file php tersebut adalah:

http://cintaprogramming.com/xx.php

maka kita set dengan cara mengunjungi (menggunakan browser atau curl):

https://api.telegram.org/botTOKEN/setWebhook?url=https://cintaprogramming.com/xxx.php

Anda akan mendapatkan balasan:

{"ok":true,"result":true,"description":"Webhook was set"}

Jika ingin kembali menggunakan metode polling, maka set URL menjadi kosong:

https://api.telegram.org/botTOKEN/setWebhook?url=

Anda akan mendapatkan balasan:

{"ok":true,"result":true,"description":"Webhook was deleted"}

Atau jika memang belum diset:

{"ok":true,"result":true,"description":"There is no webhook to delete"}

Berikutnya terserah Anda bagaimana ingin memproses data masukan dari pengguna, misalnya bisa query ke database, bisa melakukan komputasi, dsb.

Jika kode Anda jalan di versi lokal/polling, tapi tidak ketika menggunakan webhook, maka Anda perlu mendebug. Pertama test apakah: webhook dipanggil oleh telegram (bisa dicoba dengan menuliskan isi $entityBody ke file). Kedua cek apakah Anda bisa memanggil send_reply. Beberapa hosting mematikan file_get_contents untuk mengakses HTTP/HTTPS, atau mendisable modul SSL (untuk kasus ini, mungkin harus diganti memakai modul curl) . Coba skrip paling sederhana di atas sebelum menambahkan kode custom Anda untuk reply (misalnya Anda mengakses MySQL, siapa tahu kode Anda yang error karena salah database atau salah query).

Saran saya: gunakan polling dulu sampai yakin sudah benar, setelah itu baru gunakan webhook.

Contoh ini sebenarnya adalah penyederhanaan sebuah kamus. Seharusnya bot ini membalas dengan definisi dari database, tapi di contoh ini bot selalu membalas dengan “definisi ” + KATA.

Sebuah bot bisa memiliki banyak perintah yang diawali dengan “/” (slash), terserah pembuat bot yang mendefinisikan. Misalnya jika kita membuat bot cuaca, kita bisa membuat perintah: “/cuaca NAMAKOTA” (untuk mendapatkan cuaca saat ini) atau “/ramalan NAMAKOTA” (untuk mendapatkan ramalan seminggu). Untuk menangani perintah-perintah ini kita bisa menggunakan parsing teks sederhana. Contoh parsing yang bisa dilakukan split teks menjadi kata-kata: jadikan kata pertama menjadi lower case, dan trim (hapus spasinya), lalu cek apakah sama dengan “/cuaca” atau “/ramalan”. Dan berikutnya lakukan aksi sesuai dengan perintahnya.

Setelah kita memiliki perintah-perintah tersebut. Kita bisa mendaftarkan perintahnya ke BotFather supaya Telegram bisa melakukan autocomplete perintah ketika user mengetikkan karakter /.

Demikian tutorial singkat bot Telegram. Jika ada pertanyaan, silakan tinggalkan di bagiann komentar, dan akan berusaha saya jawab (atau mungkin akan saya buatkan tutorial bagian kedua untuk menjelaskan lebih detail).

Sencha Touch di PlayBook

Ini catatan teknis mempackage aplikasi Sencha Touch menjadi file .bar PlayBook. Pertama download dulu Sencha Touch 2, dan Juga SDK Toolsnya.

Saya memakai Mac, tapi tutorial ini berlaku juga untuk OS Windows. Perhatikan bahwa Anda perlu punya web server terinstall. Di Mac, Apache sudah ada default. Di Windows, silakan install IIS atau Apache (misalnya dari Wamp).

Extract file sencha-touch-2.0.1.1-commercial.zip. Saya mengekstraknya di dalam ~/Sites/ , lalu saya rename jadi “sencha” saja, jadi file-file sencha-touch-all.js, sencha-touch.js dsb ada di ~/Sites/sencha/.

Berikutnya kita buat aplikasi hello world. Sekarang dari dalam ~/Sites/sencha kita bisa menjalankan perintah “sencha generate app” untuk membuat aplikasi:

$ cd ~/Sites/sencha/
$ sencha generate app --name=HelloWorld -p ~/Sites/helloworld

Aplikasinya bisa dites dengan mengakses di http://localhost/~yohanes/helloworld (atau tergantung setting web server Anda bagaimana).

Saya tidak akan mengubah file-filenya, jadi saya langsung package saja. Pertama buat dulu file config.xml. Saya memakai file template yang sudah biasa saya pakai. Sebenarnya baris-baris feature itu tidak diperlukan untuk ini, tapi karena saya sering lupa menambahkan baris tersebut ketika memakai API Blackberry, saya selalu menggunakan template ini.

Catatan: saya tidak menggunakan ikon untuk aplikasi ini (blank). Silakan ditambahkan sendiri jika dibutuhkan.

<?xml version="1.0" encoding="UTF-8"?>

<widget xmlns="http://www.w3.org/ns/widgets"
   xmlns:rim="http://www.blackberry.com/ns/widgets"
   version="1.0.0.0" id="helloworld" xml:lang="en">

   <name>Sencha Hello</name>
   <description>Sencha Hello.</description>
   <author rim:copyright="2012" email="[email protected]">Yohanes Nugroho</author>

   <rim:orientation mode="landscape" />

   <content src="index.html"/>
   <rim:category name="Games"/>

   <feature id="blackberry.app" required="true" version="1.0.0.0"/>
   <feature id="blackberry.app.event" required="true" version="1.0.0.0"/>
   <feature id="blackberry.system" required="true" version="1.0.0.0"/>
   <feature id="blackberry.system.event" required="true" version="1.0.0.0"/>
   <feature id="blackberry.ui.dialog" required="true" version="1.0.0.0"/>
   <feature id="blackberry.utils" required="true" version="1.0.0.0"/>
   <feature id="blackberry.invoke" required="true" version="1.0.0.0"/>
   <access subdomains="true" uri="*">
   </access>
</widget>

Sekarang kita bisa men-zip aplikasinya. Masalah utama adalah: tools webworks tidak suka dengan file yang memiliki nama dengan tilde (~) dan dengan at(@) (misalnya [email protected], ini untuk retina display). Ada beberapa file seperti ini, untungnya ini tidak diperlukan, jadi kita bisa kecualikan dari file zip

zip -r senchahello.zip config.xml app.js app.json index.html resources/ sdk/ app/ -x *2x* -x *~*

Kuncinya ada pada “-x *2x* -x *~*” untuk meng-exclude file yang tidak valid menurut webworks.

Berikutnya kita bisa mempaketkan file zip tersebut menjadi file bar. Untuk mempersingkat command line, saya menginstall SDK di home directory saya di direktori webworks-tablet.

~/webworks-tablet/bbwp/bbwp senchahello.zip -g password -v buildId 1

Catatan: jika versi tidak diubah, buildId perlu dinaikkan setiap kali build.

Sekarang file .bar akan tercipta dalam direktori ~/Sites/helloworld/bin siap untuk diinstall ke PlayBook.

Catatan Teknis – Baby Coloring Book

Setiap kali saya membuat aplikasi dengan teknologi yang baru, biasanya saya mendapati banyak tantangan teknis. Dalam konteks ini “baru” bisa berarti teknologinya benar-benar baru, atau saya yang baru saja mengenal teknologi tersebut. Kali ini saya ingin membahas mengenai aplikasi saya di appworld, Baby Coloring Book.

Ide dari aplikasi ini sangat sederhana: buku mewarnai untuk bayi (terutama di bawah 3 tahun), hanya perlu menyentuh saja untuk mewarnai, tidak perlu menggosok-gosok seperti memakai krayon. Jika saya menggunakan teknologi lain untuk membuat ini (misalnya flash atau C++), saya akan menggunakan pendekatan sederhana: buat gambar tidak berwarna, gunakan flood fill untuk mengisi area. Tapi saya menggunakan HTML5 untuk membuat aplikasi ini. Alasan utamanya adalah untuk belajar mengenal lebih jauh HTML5. Saya tidak menggunakan library selain selain JQuery.

Contoh Gambar

Di Stack Overflow sudah ada yang menjawab bagaimana mengimplementasikan flood fill dengan JavaScript menggunakan Canvas:

How can I perform flood fill with HTML Canvas?

Jadi saya coba itu di PC menggunakan browser Google Chrome. Manipulasi piksel di Google Chrome sangat cepat, tapi saya melihat ada sedikit delay. Saya langsung curiga: jangan-jangan jika saya coba di PlayBook akan sangat lambat. Ternyata benar: sangat lambat.

Ada beberapa pendekatan yang terpikir oleh saya supaya aplikasi ini bisa dibuat dengan HTML5 tapi tetap cepat, tapi saya memiliki beberapa requirement:

  1. Saya tidak ingin “membatik” mendefinisikan setiap area gambar yang bisa diwarnai. Jika saya punya gambar, saya ingin langsung bisa memakai gambar itu tanpa edit manual. Dengan pendekatan flood fill, algoritma tersebut bisa otomatis mewarnai sebuah area yang dibatasi pixel tertentu (seperti mewarnai dengan “ember” di Ms Paint).
  2. Saya ingin bisa membuat gambar yang warnanya seperti diwarnai dengan krayon, jadi tidak polos.

Continue reading

Pentingnya memahami Ilmu Informatika secara menyeluruh

Hari ini saya menemukan link ke sebuah pertanyaan menarik di Stack Overflow. Sebuah pertanyaan sederhana: mengapa menjumlahkan elemen yang nilainya kurang dari nilai tertentu dalam array yang terurut, lebih cepat dari melakukan operasi yang sama pada array yang tidak terurut. Lebih jelasnya silakan baca pertanyaan dan jawabannya di sini:

Why is processing a sorted array faster than an unsorted array?

Ada beberapa hal menarik dari jawaban pertanyaan tersebut.

Pertama: meskipun Anda memprogram high level sekalipun (menggunakan Java/Ruby/Python, atau bahasa lain yang menggunakan JIT), Anda akan tetap dibatasi oleh hardware. Anda tetap perlu mengerti hardware untuk membuat aplikasi yang performasinya tinggi.

Kedua: perhatikan bahwa dengan mengetahui sebab dari masalah, kita bisa mempercepat program, tanpa menggunakan sorting. Cukup dengan menggunakan manipulasi bit yang menghilangkan branching. Kita ingin menghilangkan sorting, karena sorting sendiri butuh waktu.

Ketiga: dalam kasus tertentu, compiler bisa mengoptimasi jika diberi flag yang tepat. Tapi kita tidak bisa menggantungkan diri pada compiler saja. Compiler yang berbeda menghasilkan kode yang berbeda, dan hasilnya bisa sangat jauh berbeda. Misalnya disebutkan bahwa compiler Visual C++ 2010 tidak bisa mengoptimasi kodenya, sedangkan compiler Intel bisa melakukannya dengan sangat baik.

Keempat: Perhatikan juga bahwa optimasi compiler dibatasi oleh hardware. Hardware tertentu (misalnya Intel sejak Pentium Pro) mendukung instruksi conditional move (di assembly Intel, instruksi ini disebut dengan CMOV) yang tadinya perlu manipulasi bit manual (AND, OR, dsb). Anda tidak bisa menggunakan optimasi ini di semua hardware, apalagi jika Anda menargetkan CPU model lama (banyak digunakan di embedded device).

Mungkin sebagian dari Anda mengira pertanyaan tersebut agak mengada-ada: untuk apa mencari jumlah bilangan yang kurang dari N dan dilakukan berulang-ulang, kalau sekali saja kan hanya butuh beberapa milidetik. Dan berbeda beberapa milidetik saja kan harusnya tidak berpengaruh bagi user.

Saya terpikir beberapa aplikasi dalam dunia nyata yang mungkin membutuhkan penjumlahan secara cepat tapi berulang-ulang. Saya berikan contoh kecil: Misalnya Anda punya aplikasi interactive data viewer, dengan slider yang bisa diubah nilainya dengan mouse (sangat cepat)

  1. Anda punya array yang berisi daftar jumlah gaji semua orang pegawai di sebuah kota (arraynya tidak terurut)
  2. Kita ingin menampilkan secara interaktif: jika saya set slider ke nilai 1 juta, maka saya akan melihat bahwa total gaji semua orang yang dibawah satu juta adalah X
  3. saya bisa mengubah nilai di slider, dan menghitung ulang total semua orang yang gajinya di bawah 2 juta. Saya bisa menaik turunkan slider dengan sangat cepat, ratusan kali per detik nilai slider bisa berubah.

Perhatikan bahwa meskipun contoh ini hanya menyatakan kurang dari X, tapi sebenarnya berlaku juga untuk operasi lebih dari X, atau X dalam range tertentu.

Dalam contoh ini: perbedaan interaksi antara beberapa milidetik dan beberapa puluh milidetik bisa sangat terasa. Jadi mengerti untuk mengurutkan data (atau menggunakan trik manipulasi bit) sebelum menjumlahkan bisa membuat interaksi semakin smooth. Menggunakan database untuk tujuan animasi yang sangat smooth seperti itu tidak akan berhasil (latensinya sangat tinggi), apalagi misalnya devicenya kemampuannya processing/komputasinya rendah (misalnya tablet atau smartphone).

Sebenarnya saya bisa menunjukkan contoh yang lebih kompleks lagi (misalnya dalam hal komputasi piksel grafik), tapi nanti pembahasannya akan ngelantur ke mana-mana. Hal yang ingin saya tekankan adalah: ada banyak persoalan serupa dalam dunia nyata semacam ini. Ini adalah penyederhanaan, supaya inti masalah bisa dilihat lebih jelas.

Seringkali jika ada yang menunjukkan bahwa optimasi seperti ini diperlukan, jawaban programmer yang malas adalah: beli saja hardware yang lebih cepat, masalahnya kan beres. Perlu dicatat juga: bahwa membeli hardware yang lebih cepat tidak selalu menjadi solusi.

Misalnya Anda menjual aplikasi Anda di Apple appstore, Anda harus mendukung hardware terlambat sampai tercepat. Jika Anda bandingkan iPad generasi pertama dan kedua, maka perbedaan hardwarenya sangat jauh: memori menjadi 2x lipat, prosessor menjadi jauh lebih cepat (dari single menjadi dual core). Anda bisa mengabaikan 14.8 juta pengguna iPad 1, tapi penjualan aplikasi Anda bisa menurun jauh.

Mungkin Anda terpikir untuk melakukan komputasi di server saja. Tapi berapa delay karena latensi jaringan? apakah kecepatannya cukup acceptable untuk membuat interaksi yang smooth?

Jika saya rangkum, semua hal tersebut menunjukkan: betapa perlunya kita belajar ilmu informatika atau computer science secara baik dan menyeluruh. Misalnya dalam contoh yang sangat kecil ini:

  1. Dalam arsitektur komputer, kita belajar mengenai batasan hardware, bagaimana arsitektur CPU superscalar bekerja.
  2. Dalam pelajaran algoritma, kita belajar mengenai kompleksitas algoritma. Bagaimana memilih algoritma yang baik.
  3. Dalam pelajaran compiler, kita bisa tahu optimasi apa yang bisa (dan tidak bisa) dilakukan oleh compiler
  4. Dalam pelajaran networking, kita bisa tahu mengenai latensi jaringan (jika ingin memindahkan komputasi ke server)

Jadi menurut saya, orang-orang yang ingin membatasi pelajaran komputer hanya dengan materi yang praktis saja, tidak akan berhasil.

Manipulasi bit bagian 1: representasi biner

Kemarin buku yang saya tunggu-tunggu akhirnya tiba juga: The Art of Computer Programming, Volumes 1-4A Boxed Set (Box Set). Dulu waktu kuliah, saya sudah membaca sebagian buku ini, tapi buku ini berat di matematika, jadi kebanyakan saya hanya membaca bagian algoritmanya saja, sambil mencoba-coba sedikit latihannya. Terinspirasi dari banyak programmer di buku Coders at work yang menyukai buku ini, dan minimal memakai buku ini sebagai referensi, maka saya sekarang berusaha membaca ulang koleksi buku Knuth, plus membaca volume yang baru: Volume 4a.

Sebagai catatan: dalam wawancara Knuth sendiri tidak menyarankan seseorang membaca buku ini dari sampul ke sampul sampai habis. Saya membaca buku ini pertama skimming dulu, mencari topik menarik, setelah itu baru saya baca teliti bagian-bagian yang saya perlukan. Jadi jika Anda merasa berat membaca buku ini: coba langsung skip ke bagian yang menarik.
Continue reading

Tools untuk debugging

Di posting ini saya sekedar ingin sharing metode dan tools yang biasa saya pakai untuk debugging program. Di lingkungan yang ideal, kita seharusnya punya debugger yang canggih, cepat dan reliable, tapi sayangnya sering kali ini tidak tersedia. Ini contoh beberapa lingkungan pengembangan yang “mengesalkan” yang pernah saya jumpai:

  • Symbian versi awal (versi 6): untuk bisa mendebug, perlu IDE khusus dengan license khusus yang mahal. Symbian versi terbaru sudah semakin baik (tapi sekarang ini Symbian sudah akan berakhir).
  • BlackBerry: startup time debugger sangat lama, dan debugger sering error. Setiap kali menginstall versi program baru di BlackBerry, perlu restart (butuh sekitar 5 menit tiap kali restart).
  • Mendebug aplikasi Android di emulator. Startup emulator sangat lambat (bahkan di processor AMD quad core 3 ghz memori 16 GB) , lebih cepat mencoba langsung di HP. Masalahnya adalah ketika ada laporan: ada bug kecil di Android versi 2.2, tapi HP saya memakai Android 2.3
  • Debugging PHP di web hosting. Kadang ada masalah yang hanya muncul di web hosting, tapi tidak muncul ketika dicoba di server sendiri. Beberapa kemungkinan adalah karena versi PHP yang tidak sama, versi library yang tidak sama. Di server sendiri bisa mudah menginstall Xdebug, tapi tidak tersedia di tempat hosting.
  • Nurit Point Of Sales. Device ini banyak bugnya, tidak tersedia debugger, dan jika crash, akan memprint isi memori di atas kertas thermal sekitar 1/2 meter.
  • Kernel FreeBSD. Ketika porting tahap awal, sangat sulit mendebug apa yang terjadi di level CPU. Masalahnya karena saya tidak menggunakan development board yang memiliki JTAG.

Sebenarnya tidak semua lingkungan itu benar-benar mengesalkan jika kita punya uang, contohnya: jika saya punya uang beberapa ribu dollar, saya akan bisa mendebug Symbian dengan mudah. Jika saya punya beberapa HP Android berbagai versi, debugging Android juga lebih mudah. Jika saya punya development board resmi dengan JTAG, porting kernel akan lebih mudah. Jika saya hosting VPS dengan versi PHP saya sendiri, maka tidak akan ada masalah dengan PHP, dan andaikan ada masalah, saya bisa menginstall XDebug. Pada kenyataannya seringkali tidak tersedia dana untuk menyelesaikan berbagai masalah tersebut.
Continue reading

Berpikir Ketika Memprogram dan Menguji Program

Setelah membaca posting reddit ini, saya teringat kembali pada buku Programming Pearl, terutama bagian yang dibahas dalam posting itu yaitu mengenai binary search. Dalam buku programming pearl dinyatakan bahwa para programmer professional yang diberi waktu 2 jam untuk menulis binary search, 90% memiliki bug (terutama di *boundary* condition). Penulis blog memberi tantangan pada pembacanya untuk membuat binary search, boleh beberapa jam, tapi *tanpa testing* sama sekali.

Respon kebanyakan orang bisa dirangkum menjadi tiga kubu. Kubu pertama: ah di dunia nyata kan orang pasti testing, keahlian buat memprogram dengan benar tanpa testing itu tidak berguna. Kubu kedua menyatakan: kalau program sependek itu tidak bisa dibuat tanpa testing, bagaimana mungkin bisa membuat program besar yang rumit, apakah tiap baris program harus ditest?. Kubu terakhir menyatakan: buat apa sih membuat binary search, kan sudah ada di library/API?

Untuk kubu terakhir, jawabannya sederhana: ada kasus di mana hal tersebut masih diperlukan. Misalnya fungsi binary search di library kebanyakan tidak menyatakan elemen mana yang akan dikembalikan jika ada lebih dari 1 data yang cocok, dan tidak akan mengembalikan lokasi di mana data bisa disisipkan jika data belum ada. Contohnya di fungsi bsearch di C (POSIX):

The bsearch() function returns a pointer to a matching member of the array, or NULL if no match is found. If there are multiple elements that match the key, the element returned is unspecified.

Kadang diperlukan fungsi yang mengembalikan elemen pertama yang cocok, atau terakhir yang cocok, atau bahkan elemen random dari antara semua elemen yang cocok. Tentu saja salah satu solusinya adalah membungkus fungsi bsearch, lalu mencari ke depan atau belakang sampai tidak cocok lagi. Tapi dalam hal ini Anda juga tetap perlu memperhatikan batas index ketika mencari, jadi Anda tetap perlu menulis kode (yang perlu testing dan perlu dipikirkan).

Jika Anda mengimplementasikan fungsi binary search sendiri, Anda bisa membuat fungsi yang sekaligus mengembalikan posisi elemen di mana kita harus menyisipkan elemen tersebut jika elemen tidak ditemukan (ini bisa didapat dari lokasi perbandingan terakhir), dalam kasus ini kita tidak bisa membungkus fungsi bsearch, karena fungsi tersebut hanya mengembalikan NULL jika elemen tidak ditemukan.

Beberapa Pelajaran yang bisa dipetik dari posting dan diskusi adalah: testing itu perlu, bahkan untuk program kecil sekalipun. Pelajaran kedua adalah: kita tetap harus teliti dan berpikir ketika memprogram. Pelajaran ketiga adalah: meski isi library di berbagai bahasa sudah cukup lengkap, mengerti algoritma sederhana itu perlu, dan kadang kita perlu mengimplementasikan algoritma tersebut atau variannya.

Sebagian orang berpikir: ah tidak perlu terlalu teliti ketika memprogram, nanti akan ketauan salahnya ketika testing. Sebagian lagi berpikir: program ini sudah saya pikirkan, jadi gak perlu ditest. Sikap yang benar adalah: kedua hal tersebut berhubungan, kita harus teliti ketika memprogram, dan harus teliti juga dalam membuat testing. Mengapa tidak menggantungkan diri pada testing saja? ada beberapa masalah dengan testing, pertama testing itu sulit, untuk membuat test case yang baik perlu kasus yang sangat besar dan kedua testing tidak selalu bisa dilakukan.
Continue reading

Kritik PHP

PHP merupakan bahasa yang kurang bagus, designnya tidak dipikirkan dengan matang. Banyak sekali keanehan PHP dibanding bahasa lain, dan meskipun PHP sudah mulai agak membaik di versi 5.3 (yang baru dirilis 3 minggu yang lalu), saya masih menunggu PHP6 untuk mencoba lagi.

Kebanyakan orang tidak menyadari bahwa mereka butuh sesuatu, atau bahwa sesuatu itu jelek, sampai mereka diberikan sesuatu yang lebih baik. Di artikel ini saya ingin mengkritik PHP, tapi sebelumnya akan saya contohkan apa yang saya maksud dengan melihat sejarah MySQL.

Awalnya MySQL tidak mendukung transaksi. Komentar pendukung MySQL waktu itu: transaksi itu tidak perlu, yang penting cepat (Bahkan pembuat mysql pun berpikir demikian, coba lihat http://www.genome.ou.edu/mysql_manual.html#Bugs, bagian ” Some things we don’t have any plans to do”). Tapi kemudian transaksi ditambahkan, dengan catatan: kalau mau cepat jangan pakai transaksi. Lalu berikutnya: transaksi adalah salah satu fitur yang kami banggakan.

Nah, saya cukup yakin, isi kritik saya ini kemungkinan akan banyak ditolak oleh orang yang cinta buta pada PHP, setidaknya saat ini. Tapi ketika PHP sudah berkembang, baru akan bisa diterima. Memang begitulah sifat penggemar sesuatu, jadi saya bisa memakluminya.

Saya sendiri pernah memprogram PHP dari sejak PHP3, lalu PHP4, dan sampai awal PHP5. Semakin lama saya mempelajari dan memakai PHP, saya semakin merasakan keterbatasannya. Saya tidak menyangkal bahwa PHP merupakan bahasa yang sangat populer. Namun tidak semua yang populer itu bagus (ingat DBase? Ingat Visual Basic 6? dsb). Bagi pencinta PHP, Anda mungkin bisa berbangga PHP semakin membaik, meski caranya dengan “tambal sulam”, dan meski Anda harus sering menyesuaikan program agar berjalan di PHP terbaru. Mungkin saya akan mencoba lagi PHP di versinya yang keenam, tapi saat ini mari kita bahas satu persatu kelemahan PHP.

Continue reading

DataStore di Google AppEngine (RDBMS bukan segalanya)

Google AppEngine adalah sebuah layanan Google, di mana kita bisa membuat aplikasi dalam Python atau Java (atau bahasa lain yang memakai virtual machine Java) di infrastruktur milik Google. Secara teori, Anda akan bisa melayani 5 juta pengunjung per bulan secara gratis. Anda bisa membayar ekstra jika ingin mendapatkan resource yang lebih banyak.

Saya akan menceritakan salah satu pengalaman development dengan google appengine, yaitu mengenai bagian pembuatan aplikasi yang scalable, dengan fokus pada DataStore. Menurut saya DataStore merupakan implementasi penyimpanan data yang menarik, yang berbeda dari database relasional yang umum dipakai saat ini.

Ilmu relational database dan SQL hampir tidak dipakai sama sekali di sini. Bahkan operasi Join yang sangat lazim di basis data tidak bisa dilakukan dengan DataStore. Lalu apa kelebihan DataStore? datastore memiliki aneka batasan yang memungkinan Google mendistribusikan data di berbagai server di seluruh dunia. DataStore diiimplementasikan di atas teknologi google yang sudah terbukti, yaitu BigTable.

Continue reading