Code Obfuscation

Code Obfuscation adalah salah satu bentuk proteksi agar kode sulit dibongkar orang lain. Inti dari obfuscation adalah menyamarkan/membuat kode sulit dibaca. Obfuscation bisa dilakukan manual atau dengan tool yang disebut “obfuscator”. Sementara itu dari sisi reverse engineering, proses mengembalikan dari bentuk samar ini disebut “deobfuscation”.

Arti kata “samar” di KBBI

Meskipun kata “samar” sepertinya cukup berpadanan dengan “obfuscated” saya akan tetap menggunakan istilah inggrisnya di posting ini.

Di posting ini saya hanya ingin memberikan beberapa ilustrasi nyata seperti apa obfuscation ini. Untuk para programmer, ini bisa membantu memproteksi  program, dan untuk para reverse engineer bisa berusaha memahami bagaimana obfuscation dilakukan.

Contoh obfuscated code

Obfuscation

Jika kita punya dua fungsi sederhana seperti ini:

int search(int element, int *data, int count)
{
    for (int i =0; i < count; i++) {
          if (data[i] == count)
                return i;
    }
    return -1;
}

int replace_first(int element, int replacement, int *data, int count)
{
    int pos = search(element, data, count);
    if (pos !=-1) {
        data[pos] = replacement;
        return 1;
    }
    return 0;
}


Bentuk obfuscation pertama adalah dengan mengganti nama menjadi nama lain. Ini bisa jadi nama yang sangat singkat misalnya “a”. Pada kode yang dikompilasi menjadi bahasa mesin, nama ini bahkan tidak ada lagi karena tidak diperlukan. Pada bahasa lain yang tidak dicompile jadi bahasa mesin (seperti Java dan Python), nama ini akan tetap ada.

Tanpa membaca kodenya, sudah sulit menebak apa fungsinya ini

int a(int a1, int *a2, int a3);
int b(int a1, int a2, int *a2, int a3)

Bahasa tertentu (seperti Java/C++) mendukung overloading. Beberapa fungsi bisa memiliki nama sama asalkan parameternya berbeda:

int a(int a1, int *a2, int a3);
int a(int a1, int a2, int *a2, int a3)

Cara lain adalah dengan mengubah namanya menjadi menyesatkan, misalnya kedua nama seperti di atas diubah menjadi seperti ini (perhatikan bahwa sengaja count-nya dipindah ke depan untuk menyesatkan pembacanya).

int clear(int count, int *data, int position);
int remove_range(int start, int end, int *data, int element);

Selain penggunaan nama yang menyesatkan, cara lain adalah dengan mengubah control flow program. Contoh sederhananya seperti ini, kita memanggil beberapa fungsi berurutan:

verify_license();
initialize_printer();
initialize_camera();
connect_to_database();

Jika sebuah bahasa mendukung goto maka bentuk obfuscationnya bisa seperti ini:

verify_license();
goto label2;

label1:
initialize_camera();
connect_to_database();
goto label4;

label2:
initialize_printer();
goto label1;

label4:

Jika suatu bahasa tidak mendukung goto urutan operasi bisa disamarkan dengan loop dan switch:

int order[] = {3,1,2,0};
for (int i =0; i < 4; i++) {
   switch (order[i]) {
        case 0: connect_to_database(); break;
        case 1: initialize_printer(); break;
        case 2: initialize_camera(); break;
        case 3: verify_license(); break;
   }
}

Obfuscation kecil seperti contoh di atas masih mudah dimengerti untuk kode yang pendek. Untuk kode yang besar, jumlah “case”-nya bisa puluhan, dan masing-masing nama fungsinya tidak jelas.

Beberapa obfuscation bisa mudah dilihat jika data atau string terlihat jelas, misalnya jika ada kode seperti ini, meskipun kita tidak tahu apa itu kelas x, tapi terlihat bahwa fungsi saat ini berhubungan dengan enkripsi AES:

            throw new x("AES decrypt error");

Jadi bentuk obfuscation berikutnya adalah: string encryption supaya tidak mudah mencari string di dalam program dan mempersulit pemahaman. Tentunya string ini harus bisa didekrip ketika program berjalan, hanya mempersulit pemahaman program.

            throw new x(decrypt(ConstString.ERR1));

Teknik-teknik lain juga bisa ada banyak, saya tidak akan memberikan contoh kode satu persatu. Beberapa yang bisa dilakukan misalnya

  1. Obfuscation di level bahasa mesin/bytecode
  2. Menggunakan exception untuk control flow obfuscation
  3. Menyisipkan kode sampah, misalnya mengurutkan elemen, lalu mencari elemen tengah, menjumlahkan semua elemen, lalu hasilnya tidak dipakai
  4. Menggunakan thread untuk memecah algoritma menjadi beberapa bagian sehingga lebih sulit di mengerti
  5. Mengubah logika program, misalnya menambahkan angka 2312312 di awal, lalu di akhir dikurangi lagi 2312312
  6. Menggunakan enkripsi dan/atau kompresi untuk sebagian kode program yang diload secara dinamis
  7. Memakai custom virtual machine

Perlu diperhatikan bahwa obfuscation tertentu bisa membuat program jadi lebih lambat. Sekedar mengganti nama method tidak akan membuat lebih lambat (bahkan biasanya malah membuat sedikit lebih cepat), tapi mengganti control flow biasanya membuat kode menjadi lebih lambat. Obfuscation juga membuat debugging menjadi lebih sulit (karena memang itu tujuannya). Jadi sebaiknya obfuscation hanya dilakukan di akhir development.

Saya tidak bisa menyarankan tool obfuscator tertentu karena memang jarang melakukan obfuscation pada kode saya, silakan search “obfuscator” dan nama bahasa yang Anda pakai di search engine. Tool obfuscator yang banyak saya temui adalah  Proguard (gratis) yang dipakai untuk kode Java/Android.

Di dunia Javascript ada istilah minifier, yaitu tool untuk membuat kode Javascript mejadi lebih kecil. Ini dilakukan dengan mengganti nama variabel, menghapus spasi, komentar dsb. Secara umum ini juga berfungsi sebagai obfuscator sederhana.

Deobfuscation

Secara umum tidak ada cara generik yang membuat obfuscated code bisa dibaca dengan mudah. Tapi ada beberapa tool yang bisa membantu proses deobfuscation spesifik untuk bahasa/teknologi tertentu.

Contohnya jika bertemu dengan kode JavaScript yang sudah minified, maka kita bisa memakai JavaScript beautifier. Ini tidak bisa mengembalikan nama variabel, hanya membuat teks yang sulit dibaca menjadi lebih mudah dibaca (tool beautifier ini sekarang sudah built in di Developer Tools-nya Google Chrome).

Contoh lain: ada yang membuat tool untuk mendekrip String untuk APK yang ditulis dalam Java. Tapi tool ini tidak selalu jalan untuk semua protektor. Setiap kali ada yang membuat tool untuk otomasi sesuatu, pembuat obfuscator menambahkan satu hal kecil sehingga toolnya harus diupdate (atau bahkan ditulis ulang).

Cara yang pasti berhasil adalah kombinasi manual dengan debugger dan sedikit programming.  Hal utama adalah memahami obfuscation apa yang dilakukan: apakah stringnya dienkripsi, apakah nama methodnya diubah, apakah control flow-nya berubah, dsb.

Jika sekedar nama methodnya diubah, maka kita harus membaca kodenya dan melakukan renaming untuk mendapatkan nama yang benar. Ini bisa dilakukan berdasarkan beberapa hal, misalnya:

  • string yang muncul (misalnya “AES Error” mengindikasikan AES)
  • konstanta yang dipakai (misalnya 0x9E3779B9 mengindikasikan penggunaan enkripsi XTEA)
  • fungsi yang memanggil. Misalnya jika suatu fungsi dipanggil dari fungsi AES, maka kemungkinan itu hanyalah subrutin AES
  • fungsi yang dipanggil, misalnya jika aplikasi C memanggil “system” maka kemungkinan ini fungsi menjalankan command line lain
  •  algoritma yang dipakai. Beberapa algoritma sederhana (search, sort, traversal) mudah diidentifikasi

Untuk mendapatkan gambaran sebuah program seperti menyusun sebuah puzzle. Kita bisa mulai dari bagian-bagian yang jelas. Untuk puzzle bagian yang jelas adalah pinggiran puzzle, dan bagian-bagian yang unik. Untuk program kita bisa mulai dari titik awal program (main di sistem POSIX, Activity di Android, dsb), dan titik di mana program memanggil fungsi eksternal.

Jika string dienkripsi, kita bisa membuat breakpoint di method dekrip-nya agar bisa mendapatkan hasil string-nya. Jika control flow-nya obfuscated, kita bisa membuat beberapa breakpoint untuk berhenti di tiap titik, jadi kita bisa mengetahui urutan yang sebenarnya. Selain menggunakan breakpoint dan debugger, kita juga bisa menggunakan Frida atau tool sejenis.

Penutup

Walaupun obfuscator bisa membantu melindungi program, tapi faktor keamanan lain harus tetap diperhatikan. Attacker yang gigih akan bisa membuka segala jenis obfuscation, hanya akan memperlama saja. Di kasus tertentu kombinasi obfuscator dan pentester yang kurang berpengalaman justru bisa membuat aplikasi kurang aman karena testing aplikasi kurang optimal.

Contohnya begini: aplikasi memakai enkripsi, lalu kodenya diobfuscate.  Aplikasi ini ditest oleh pentester yang tidak bisa melakukan reverse engineering terhadap kode tersebut, dan pentester menganggap aplikasi tersebut aman karena dia tidak dapat melakukan tampering terhadap nilai yang dikirimkan. Ketika aplikasi dirilis dan dibongkar oleh seorang reverse engineer yang berpengalaman, dia dapat mengubah nilai yang dikirimkan dan ternyata tidak dicek di sisi server (aplikasinya jebol).

Jadi sebaiknya: pentester diberi akses pada kode yang belum obfuscated dan kode final yang sudah. Ini akan lebih optimal karena kerja pentester lebih cepat, tidak perlu membongkar obfuscation dan lebih aman (seluruh fungsi bisa ditest dengan baik). Ini dengan asumsi bahwa pentester memiliki keahlian untuk membaca kode dengan baik.

Semoga artikel singkat ini bisa memberikan gambaran mengenai apa itu code obfuscation dan berbagai batasannya.

Mendalami Bahasa C

Saya memberikan saran agar seseorang “mendalami bahasa C” jika ingin belajar reverse engineering. Ada pertanyaan menarik yang diajukan ke saya: sedalam apa belajarnya pak? apa yang harus dipelajari. Sesuai KBBI mendalami di sini berarti: meresapi; menyelami; mempelajari (menelaah, menyelidiki) dalam-dalam.

Saya tidak akan membahas dalam mengenai kenapa seseorang perlu memahami bahasa C, singkatnya: saat ini C masih dipakai di mana-mana, dan akan terus begitu untuk beberapa belas/puluh tahun mendatang. Kernel berbagai sistem operasi ditulis dalam C, berbagai library penting masih ditulis dalam C (library kompresi, enkripsi, image encoding/decoding, dsb), dan bahkan kebanyakan bahasa pemrograman lain diimplementasikan dalam C (misalnya Ruby, Python, dan PHP).

Di awal, pelajarilah dan pahamilah semua konsep dasar dalam bahasa C. Ini seharusnya tidak makan waktu lama. Bahasa C hanya punya beberapa tipe data dasar (void, char, short, int, long, float, dan double) masing-masing bisa signed atau unsigned. Kita bisa mendefinisikan sebuah konstanta dengan const. Tipe data lain adalah enum, union, dan struct (sudah pernah saya bahas di sini) semua tipe data bisa diberi nama dengan typedef.

Hanya ada beberapa sintaks loop (while, do while, dan for, semuanya dengan break dan continue) dan conditional (if/else, goto, dan switch/case/default). Sintaks pembuatan fungsi juga cukup sederhana, hanya perlu mengingat “return” untuk mengembalikan nilai.

Konsep manajemen memori dan string (array of characters) merupakan salah satu hal yang sering membuat pemula bingung. Jika Anda sudah berhasil membuat kode yang selalu lolos valgrind (artinya tanpa warning dan tanpa memory leak), maka Anda sudah lulus dalam pelajaran ini.

Berikutnya buatlah struktur data dalam bahasa C. Mulai dari yang sederhana seperti linked list. Setelah berhasil mencontek buku/website, cobalah menuliskan ulang struktur data tanpa mencontek. Seharusnya kalau sudah paham akan bisa. Lalu cobalah memakai fitur yang lebih rumit seperti function pointer. Pastikan ini juga lolos valgrind.

Cobalah memakai berbagai library C, bisa dimulai dari memakai berbagai fungsi di library C standar. Lalu diteruskan dengan library lain, misalnya zlib untuk kompresi data, expat untuk parsing XML, png untuk dekompresi file PNG.

Cobalah juga untuk memakai lingkungan yang berbeda. Sistem operasi yang berbeda, compiler yang berbeda, IDE yang berbeda. Supaya lebih paham yang mana yang merupakan bagian dari bahasa C, dan yang mana sekedar fitur IDE atau OS yang Anda pakai.

Menurut saya seseorang bisa dianggap cukup memahami bahasa C apabila sudah menyadari bahwa bahasa C itu sangat sederhana. Pertama yang harus disadari adalah ada bahasa C dan ada libray C.

Ketika belajar C, seseorang akan diberikan program “hello world”, seperti ini:

#include <stdio.h>

int main(int argc, char *argv){
   printf("hello world");
}

Tanpa menyadari apa itu gunanya include, dari mana printf berasal, dsb. Ketika baru belajar memang kita tidak perlu tahu itu semua, tapi jika ingin mendalami, kita harus mengerti peran: preprocessor, compiler, assembler, dan linker. Kita juga perlu memahami apa itu library, dan bagaimana membuat library sendiri (pernah saya bahas di sini).

Memprogram sistem embedded tanpa sistem operasi, misalnya microcontroller akan membuat kita sadar mengenai banyak hal yang mungkin tidak terpikirkan di desktop. Misalnya pernyataan sederhana

printf("hello world\n");

Di sistem embedded tanpa layar dan tanpa keyboard, mungkin Anda akan bertanya: ke mana outputnya? bagaimana kita membaca input?. Di sini akan disadari bahwa printf bukanlah bagian dari bahasa C, tapi bagian dari library C. Bahasa C bisa digunakan dengan berbagai library (di Linux saja ada pilihan: GNU LibC, diet libc, musl, dsb).

Di sinilah salah satu kelebihan bahasa C: ketika kita ingin tahu implementasi sebuah fungsi library apapun, kita bisa melihatnya dan biasanya dalam bahasa C juga (hanya sebagian yang memakai assembly). Beda misalnya dengan PHP: jika kita ingin tahu bagaimana fungsi strlen atau split di PHP diimplementasikan, maka yang harus kita baca adalah kode dalam bahasa C (bukan PHP).

Fungsi printf di atas sudah sangat kompleks untuk dijadikan contoh, jadi saya memakai fungsi sederhana saja: strlen. Ini implemenasi generik paling sederhana dari openbsd:

http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/lib/libc/string/strlen.c?rev=1.9&content-type=text/x-cvsweb-markup

size_t
strlen(const char *str)
{
	const char *s;

	for (s = str; *s; ++s)
		;
	return (s - str);
}

Tentunya ada ribuan cara untuk mengimplementasikan strlen. dan kadang untuk optimasi digunakan assembly. Saat ini banyak compiler C yang terbuka source codenya (GCC, Clang, Watcom, dsb) dan juga semua librarynya, jadi semua internal C bisa dipelajari.

Khusus untuk yang ingin belajar C untuk reverse engineering. Pelajarilah bahwa biasanya compiler C bisa menghasilkan kode assembly langsung dalam bentuk teks, dan kita bisa membandingkan kode C dengan kode assembly yang dihasilkan compiler. Sebagian informasi mengenai cara menghasilkan teks assembly bisa dibaca di sini.

Sebagai penutup. Jika Anda sudah bisa menganggap bahasa C sebagai bahasa yang sederhana maka kemungkinan Anda sudah mendapatkan pencerahan dan sudah mulai paham bahasa C.

Matematika dan Programming

Di kala senggang saya masih menjawab pertanyaan via Facebook/Email/Telegram dan banyak calon programmer yang sudah takut sebelum belajar programming: apakah akan butuh matematika? Jawabannya singkatnya tergantung. Tergantung ingin memprogram apa dan sedalam apa.

Matematika dasar tentunya sangat diperlukan, misalnya perkalian, pembagian, penjumlahan pengurangan. Hampir di semua bidang diperlukan ilmu dasar geometri. Misalnya tentang sistem koordinat ketika menggambar grafik (atau sekedar mengatur posisi teks di sebuah halaman web).

Pengetahuan dasar ini penting, dan ini berarti anak yang masih sangat kecil dan belum memiliki dasar matematika harus berhenti dulu belajar di titik tertentu. Ini pengalaman saya dalam mengajari anak saya ketika dulu mengajari dia programming di usia 4 tahun (sekarang sudah 7 tahun). Logika boolean juga perlu dipahami, sekedar AND, OR, dan NOT sudah cukup untuk sebagian besar kasus.

Untuk pemrograman grafik, terutama grafik 3D diperlukan pemahaman matriks dan vektor. Segala operasi matrix akan terlihat secara visual ketika memprogram grafik. Matrik dan vektor juga dipakai di Machine Learning. Jika fokusnya ingin mengolah data besar, maka berbagai ilmu matematika seperti: statistika, linear programming, graph, dan banyak konsep yang rumit akan terpakai.

Kadang hampir semua topik matematika terpakai dalam satu aplikasi. Contohnya untuk membuat game yang kompleks, diperlukan berbagai matematika untuk grafik (matriks, vektor), dibutuhkan AI untuk menggerakkan musuh (yang butuh matriks, vektor, statistika, dsb), dan untuk mencari jalan terpendek atau terbaik kadang dibutuhkan teori graph, dan masih banyak lagi komponen sebuah game.

Saya masih bisa memberikan banyak contoh lain aplikasi matematika dalam programming, tapi hal yang paling penting adalah: matematika (selain topik yang paling dasar) bisa dipelajari selagi kita belajar memprogram.

Sebelum masuk ITB, saya dulu belajar programming otodidak mulai dari SMP. Ketika saya belajar pemrograman sambil belajar matematika SMP/SMU, saya merasa lebih bisa mengerti karena bisa dicoba dalam bentuk program. Contohnya konsep fungsi dan komposisi fungsi. Saya bisa membuat sebuah fungsi di dalam bentuk kode program yang memanggil fungsi lain, dan saya bisa bereksperimen dengan itu. Jadi konsep “fungsi” tidak lagi menjadi hal yang abstrak.

Simbol summation (∑) di kode program hanyalah sebuah loop penjumlahan. Demikian juga dengan ∏ yang hanya loop dengan isi perkalian.

Demikian juga dengan topik matriks dan vektor waktu SMU. Saya mendapatkan banyak ilmu justru dari buku cara membuat game 3D yang saya baca dan saya coba waktu itu. Topik di kelas terasa sangat abstrak, tapi di kode program, bisa terlihat apa gunanya memiliki matriks dan berbagai sifat matriks lainnya.

Kalau Anda tertarik lebih dalam lagi mengenai berbagai topik matematika yang nantinya akan terpakai, silakan baca posting panjang ini (Math for Programmers) yang sudah ditulis seseorang di tahun 2006. Artikel tersebut juga membahas secara detail bagaimana belajar matematika yang lebih baik.

Jadi kesimpulannya adalah: belajar programming bisa dimulai asalkan sudah memiliki pengetahuan matematika yang dasar. Belajar konsep lanjut bisa dilakukan sambil belajar programming, dan bagi sebagian orang belajar dengan cara ini lebih mudah. Tapi jika Anda sudah punya dasar matematika yang bagus tentunya programming akan lebih mudah lagi dan Anda bisa membuat program yang lebih baik lagi. Contohnya: jika Anda punya dasar matematika yang bagus untuk AI, maka Anda bisa membuat game dengan AI yang lebih baik dari yang tanpa AI.

Signature email jaman kuliah

Dulu waktu kuliah, saya punya signature email seperti ini:

main(i){putchar((i-1)["Xme]i_l"]+(i++))&&(8-i)&&main(i);} 


Ternyata masih ada beberapa orang yang ingat, dan masih banyak yang penasaran apa artinya (cuma satu kata: Yohanes) dan  kok bisa muncul seperti itu?.

Pertama, menurut standar C lama, sebuah fungsi tanpa kembalian akan mengembalikan sebuah int, dan parameter yang tanpa tipe juga adalah sebuah int, jadi fungsi di atas sama dengan:

int main(int i){
   putchar((i-1)["Xme]i_l"]+(i++))
         &&(8-i)&&
           main(i);
 } 

Perhatikan juga bahwa di C, sifat operator && adalah short circuit, artinya dalam A() && B() jika A() mengembalikan false, maka B tidak dieksekusi:

#include <stdio.h>

int A() {
   printf("Fungsi A dipanggil\n");
   return 0;
}

int B() {
   printf("Fungsi B dipanggil\n");
   return 1;
}

int main(int argc, char *argv[])
{
   if (A() && B()) {
           printf("A dan B mengembalikan TRUE\n");
   }
   return 0;
}

Bagian main di atas sama saja dengan ini:

#include <stdio.h>

int main(int argc, char *argv[])
{
   if (A()) {
       if (B()) {
           printf("A dan B mengembalikan TRUE\n");
       }
   }
   return 0;
}

Jadi kode signature saya bisa dijadikan if juga seperti ini:

int main(int i){
   if (putchar((i-1)["Xme]i_l"]+(i++))) {
           if (8-i) {
               if (main(i)) {
               }
           }
   }
 } 

Perhatikan beberapa bisa diperjelas, misalnya (8-i) akan true jika (8-i) !=0, atau selama i != 8. Karena if (main()) kosong, maka bisa dihilangkan if-nya.

int main(int i){
   if (putchar((i-1)["Xme]i_l"]+(i++))) {
           if (i!=8) {
              main(i);
           }
   }
 } 

Di C, sebuah array adalah sebuah pointer dan sebuah string adalah array of characters. Di C:

    int *array = (int *)malloc(sizeof(int)*10);
    int index = 1;
    array[index] = 10;
    //syntax array access di atas sama dengan:
    *(array + index) = 10;
    //penjumlahan sifatnya komutatif
    *(index + array) = 10;
    //jadi ini juga sama:
    index[array] = 10; 

Untuk lebih jelasnya, string saya keluarkan, dan notasinya diperbaiki:

const char *str = "Xme]i_l";
int main(int i){
   if (putchar(str[i-1]+(i++))) {
           if (i!=8) {
              main(i);
           }
   }
 } 

Kita lihat fungsi putchar di manual:

fputc, fputs, putc, putchar, puts – output of characters and strings

Di bagian return value:

fputc(), putc() and putchar() return the character written as an unsigned char cast to an int or EOF on
error.

Catatan: karena fungsi putchar tidak dideklarasikan, dan saya tidak menginclude apapun, maka dianggap kembaliannya int, dan ada warning dari compiler.

Dalam kasus saya, putchar ini akan selalu mengembalikan 1, karena saya memprint satu karakter setiap waktu. Jadi kita sederhanakan lagi:

const char *str = "Xme]i_l";
int main(int i){
   putchar(str[i-1]+(i++));
   if (i!=8) {
      main(i);
   }   
 } 

Operator ++ (post increment) akan dilakukan setelah sebuah ekspresi, jadi dalam kasus ini bisa disederhanakan:

const char *str = "Xme]i_l";
int main(int i){
   putchar(str[i-1]+i);
   i++;
   if (i!=8) {
      main(i);
   }   
 } 

Sekarang ke bagian “magic”-nya. Di sistem operasi Windows, Linux atau POSIX yang lain, ketika program dijalankan, maka program dalam C akan menerima jumlah parameter dan isi parameternya

int main(int argc, char *argv[])

Jika kita deklarasikan tanpa argv, maka hanya jumlah parameternya yang kita dapatkan. Meskipun biasanya namanya argc dan argv, nama parameternya tentunya boleh apa saja

int main(int jumlah_argumen)

Jika program dijalankan tanpa parameter, maka jumlah argumennya adalah 1, yaitu nama program saat ini (yang tidak kita pedulikan di program ini). Jadi sebenarnya program tersebut dipanggil dengan

main(1);

Perhatikan bahwa “main” adalah sebuah fungsi di C, dan seperti fungsi apapun, bisa dipanggil bebas. Dalam kasus ini, saya memanggil (rekursif) main, dengan nilai i yang ditambahkan terus.

Jika ingin kode yang sangat jelas tiap langkahnya seperti ini:

#include <stdio.h>

const char *str = "Xme]i_l";
int main(int i){
   printf("\ni = %d\n", i);
   printf("str[i-1] = %c +%d = %c\n", str[i-1], i, str[i-1] + i);
   putchar(str[i-1]+i);
   i++;
   if (i!=8) {
      main(i);
   }   
} 

Dan outputnya:

[email protected]:~$ ./a.out 

i = 1
str[i-1] = X +1 = Y
Y
i = 2
str[i-1] = m +2 = o
o
i = 3
str[i-1] = e +3 = h
h
i = 4
str[i-1] = ] +4 = a
a
i = 5
str[i-1] = i +5 = n
n
i = 6
str[i-1] = _ +6 = e
e
i = 7
str[i-1] = l +7 = s

Demikian keisengan jaman kuliah dulu. Sekedar tambahan: dulu terinspirasi dari International Obfuscated C Code Contest, kode saya ini sangat sederhana dibandingkan para pemenang IOCCC.

Memprogram Apa Saja

Saya punya hobi memprogram benda apa saja dengan bahasa apa saja. Pertama saya contohkan dulu benda-benda yang saya program, lalu saya akan berusaha menjelaskan kenapa saya punya hobi ini, dan kenapa menyukai hobi ini.

Saya belajar memprogram otodidak waktu kelas 2 SMP dengan komputer Apple II/e dengan bahasa Basic. Waktu itu semuanya masih ngasal karena hanya belajar dari contoh source code. Waktu floppy disk-nya sudah error, saya tetap memprogram tiap hari, iseng membuat sesuatu, walau tidak bisa disimpan dan harus diketik lagi besoknya. Akhirnya berhenti memprogram benda itu setelah mati total.

Di SMU kelas 2 saya baru punya komputer lagi, kali ini IBM PC dengan Windows 95. Di PC tersebut saya memakai Pascal dan Assembly dan juga sudah mulai memprogram memakai Delphi.  Saya mencoba berbagai macam hal di PC (pernah saya tuliskan di sini). Dari sini sudah terlihat kalau saya sangat random, dari mulai memprogram utility sampai game. Apapun yang saat itu menarik buat saya.

Waktu kuliah saya membawa PC saya ke Bandung, tapi kos saya dibobol maling dan PC saya dicuri. Akhirnya saya sering nongkong di lab sampai tutup. Lab waktu tingkat satu dulu sangat memprihatinkan, cuma 486 DX (lebih rendah specnya dari PC pentium saya yang hilang), jadi di situ saya kembali mendalami memprogram mode teks.

Device non PC pertama yang saya program adalah Palm OS. Selanjutnya banyak device sejenis PDA/Smartphone yang saya program. Saya sempat membuat puzzle di PalmOS dan beberapa app kecil lain. Berikutnya adalah Symbian Bible yang sempat dipakai jutaan orang di masa kejayaan Symbian OS (menggunakan C++). Saya juga membuat Bible Plus untuk OS Blackberry (versi BBOS ditulis memakai Java dan versi BB10 di tulis dalam C++ menggunakan Qt).

Saya juga memprogram game console saya. Saya memporting dua aplikasi ke Wii, yaitu WiiApple dan Hatari (keduanya menggunakan C di platform PowerPC). Saya membuat aplikasi dadu di Nintendo DS ketika dadu anak saya hilang (menggunakan C di platform ARM).

11224430_10154009703648488_423812051884387581_n

Sebelum ada Apple Watch, Pebble, dan berbagai jam pintar Android, saya sudah memprogram jam EZ430-Chronos untuk menampilkan OTP (ini memakai C, prosessornya MSP430). Setelah punya jam pintar Android, saya juga membuat versi untuk Android (menggunakan Java).

10689684_10152985303908488_979245536455326491_n

Program yang saya buat kadang khusus cuma untuk mainan anak saya. Misalnya benda ini adalah Arduino dengan Joystick yang akan mengubah arah panah (dan jika ditekan tengahnya akan mengubah menjadi ikon lain).

11700914_10153778798908488_3986090072574211621_n

Ini dipakai di tempat tidur busnya:

11737831_10153778798868488_6085033335527012678_n

Sekedar lampu sirene untuk mobil-mobilan anak saya (menggunakan C di ATTiny13):

10945854_10153355982928488_8889515360750762989_o

Memprogram kereta mainanya (menggunakan C):

1521933_10152323796063488_1552795962_n

Atau mainan berbasis RFID untuk Jonathan yang bisa dilihat di sini (berbasis Python).

8993376562_55ff3846b3

Di mobil, saya memasang display yang terhubung dengan raspberry pi. Karena tidak menemukan media player yang mudah dipakai anak saya, maka saya membuat player sendiri yang dikendalikan dengan Joystick NES (ini menggunakan Python+PyGame).

11741108_10153783327303488_4463593811268542014_o

Kadang saya hanya membuat program kecil yang dipakai sendiri. Misalnya ini untuk belajar ESP8266 (menggunakan bahasa Lua).

10983178_10153384149983488_5592019281940390376_n

Saya juga tidak keberatan memakai berbagai bahasa. Misalnya untuk mainan Puzzle ini, saya memakai Haxe:

IMG_00000145_thumb

Kalkulator bisa diprogram dalam bahasa BASIC

Selain aplikasi yang sifatnya main-main, saya juga melakukan beberapa hal yang agak serius, seperti memporting kernel OS. Misalnya porting FreeBSD ke sebuah SoC ARM.

Di PC, saya memprogram dalam banyak bahasa: assembly, Pascal/Delphi, C, C++, PHP, Python, Lua, Ruby, Java, JavaScript dsb. Sebagian besar yang saya tulis pernah jadi produk atau dipakai di internal perusahaan.

Bagi saya memprogram dengan berbagai teknologi memiliki kepuasan tersendiri. Ketika sebuah program bisa berjalan bagi saya itu sudah merupakan hal yang ajaib. Meskipun saya tahu bagaimana komputer bekerja sampai level bit processing dan memahami teori turing completeness, tetap saja magic.

Beberapa pengalaman terasa lebih magic dibanding sebelumnya. Kali pertama memprogram socket, rasanya takjub dua buah program di dua komputer bisa berinteraksi,  kali pertama memprogram skrip CGI (common gateway interface): wah bisa bikin situs yang dinamis, kali pertama memprogram LED yang bisa berkedip, menggerakkan motor, dan membaca sensor rasanya senang sekali sebuah program bisa berinteraksi langsung dengan dunia fisik.

Pengalaman programming juga membantu saya memahami banyak konsep matematika. Mengenal konsep fungsi di programming membuat saya lebih mudah memahami topik seperti komposisi fungsi. Belajar perkalian matriks ketika membuat game 3D lebih nyangkut di kepala saya daripada ketika belajar di kelas.

Banyak orang menggunakan berbagai alat musik untuk memainkan lagu tertentu. Sebenarnya lagunya sama saja, tapi ada kepuasan tersendiri mendengarkan musik menggunakan alat musik alternatif (misalnya ada yang memainkan Let It Go memakai Game Boy). Sama halnya dengan program: emulator Apple yang berjalan di PC sama saja dengan yang berjalan di Wii, tapi ada kepuasan tersendiri melihat program yang sama bisa berjalan di device yang berbeda. Dalam kasus emulator Apple, Wii bisa terhubung ke TV di ruang tamu dan bisa membangkitkan nostalgia dulu orang-orang memakai komputer Apple dengan monitor TV sebagai displaynya.

Kadang saya menganggap berbagai teknik yang sudah lama tak akan terpakai lagi, dan ternyata saya salah. Dulu waktu ingin membuat aplikasi berjalan di latar belakang di DOS, saya memakai mengintercept interrupt 1ch, supaya dipanggil 18.2 kali per detik. Waktu saya belajar Linux dan Windows dan kemampuan multiprocess dan multithreading, saya pikir: wah ini cara yang mudah dan enak. Tapi ketika berhadapan dengan browser: kembali ke single threading, dan beberapa hal perlu disimulasikan dengan timer. Saat ini support WebWorker sudah memungkinkan multi threading tapi tetap terbatas (contoh: akses DOM tidak bisa dari web worker, jadi processing DOM tetap harus single thread).

Meski sudah saya jelaskan, saya sadar bahwa banyak hobi yang sulit dimengerti oleh orang lain. Selalu ada counter argument kenapa hobi itu “aneh”, atau “nggak berguna”.

Contoh: hobi mendaki gunung. Penjelasannya kenapa seseorang bisa suka: mengenai perjalanannya (it’s all about the journey), mengenai udara segarnya, mengenai pemandangan indahnya. Contoh counter argument-nya: kan capek jalan naik gunung, saya baca naik gunung itu bahaya (udah banyak orang yang meninggal gara-gara tersesat), nanti cari toilet di mana? pemandangannya kan bisa dicari di Google, di taman juga udaranya segar. Saya ambil pake tour aja yang di antar bus ke puncak gunung yang lain, sama aja kan? terus kenapa harus naik gunung yang lain? bukannya pemandangannya mirip-mirip aja?

Mungkin bagi orang awam berbagai kamera sama saja, lensa yang mahal versus mahal banget tidak terlihat bedanya. Dan masih banyak lagi hal-hal lain yang cuma bisa diapresiasi pemilik hobi.

Hanya karena saya suka memprogram berbagai device tidak membuat saya jadi jago/pintar memprogram, hanya membuka pikiran saya lebih luas. Sama seperti orang yang hobi naik gunung tidak membuat orang tersebut jadi ahli, walaupun mungkin dia lebih sehat dari aktivitas mendaki dibanding yang diam saja di rumah. Dari hobi saya, saya tahu sedikit lebih banyak dari mereka yang tidak punya hobi programming.

Tulisan ini cuma sekedar sharing hobi aneh saya karena saya masih jarang ketemu orang yang senang memprogram apa saja. Siapa tahu bisa menarik orang lain untuk hobi yang sama.

Mengapa memakai bahasa pemrograman tertentu?

Mengapa seseorang memilih suatu bahasa tertentu untuk menyelesaikan suatu masalah atau membuat aplikasi tertentu? Ternyata jawabannya bisa banyak.  Kebanyakan pilihan intinya adalah keterpaksaan dan terakhir baru faktor kenyamanan.

Keterpaksaan pertama dari non teknis, misalnya dari permintaan atasan atau permintaan client. Hal ini sering kali tidak bisa ditawar lagi, terutama jika sudah melibatkan kontrak legal. Paksaan ini sering menghasilkan kode yang aneh atau tidak menggunakan fitur yang tepat dari sebuah bahasa, karena programmer dipaksa menggunakan bahasa lain, dan karena harus buru-buru mereka akan menggunakan gaya bahasa X di bahasa Y.

Sebuah teknologi tertentu kadang hanya bisa diprogram dengan satu bahasa. Misalnya dulu ponsel cuma bisa diprogram dengan Java (J2ME) jadi ya terpaksa harus memakai bahasa Java. Microcontroller tertentu perlu memakai assembly karena ukuran ROMnya sangat kecil dan tidak ada compiler C yang bisa menghasilkan kode sekecil itu.

Sekarang ini jumlah memori dan kecepatan berbagai device sudah sangat tinggi, sehingga memungkinkan interpreter berjalan di platform apa saja. Ini memberi kebebasan memilih bahasa. Contohnya: dulu microcontroller CPU dan RAMnya sangat kecil sehingga tidak cukup untuk menjalankan interpreter Python. Sekarang sudah banyak microcontroller yang bisa menjalankan MicroPython.

Bahasa tertentu dipilih karena masalah kinerja (performance). Meskipun Python bisa berjalan di microcontroller, tapi kecepatannya jauh lebih lambat dibandingkan C/C++ (karena interpreted). Faktor kecepatan ini sangat terasa untuk keperluan tertentu, misalnya untuk membuat animasi lampu yang jumlahnya banyak. Di dalam konteks lain juga sama: bahasa tertentu dipilih karena masalah performance.

Berbagai bahasa memiliki tingkat strictness yang berbeda, dan mulai masalah sintaks sampai tipe data. Sebagian bahasa memungkinkan kecerobohan yang sulit dilakukan di bahasa lain. Contoh sederhana, dalam JavaScript kita bisa membuat kode seperti ini dan akan berjalan, walau hasilnya mungkin tidak seperti yang diharapkan.

Tipe a adalah Number dan b adalah String, tapi keduanya bisa dioperasikan

Pemula Ruby yang beralih dari bahasa tertentu (misalnya C) mungkin akan bingung dengan sifat Ruby di mana 0 dianggap true. Alasannya: 0 adalah object yang valid, dan nilainya dianggap true.

Untuk bahasa yang sangat dinamik, dibutuhkan banyak test case untuk banyak hal sederhana, sedangkan di bahasa yang tipenya dicek oleh compiler, jumlah test bisa dikurangi. Ada bahasa yang lebih strict lagi, misalnya bahasa ADA yang sempat jadi bahasa wajib oleh Department of Defense Amerika. Secara umum: bahasa tertentu mengurangi kesalahan programmer (baik dari syntax, dari compiler), sehingga bahasa tersebut dipilih untuk tujuan tertentu.

Beberapa masalah mudah diselesaikan menggunakan library yang sudah ada. Ketersediaan library ini menjadi alasan kenapa memilih sebuah bahasa. Misalnya sudah ada library OpenCV (Open computer vision) untuk memproses video secara realtime (misalnya face recognition). OpenCV ditulis dalam C++ dan  ada banyak binding sehingga fungsi-fungsi C++ ini bisa diakses dari bahasa lain (misalnya Python, Java, C#, NodeJS) tapi tidak semua binding ini sempurna, dan sebagian ketinggalan versinya. Misalnya saat tulisan ini dibuat, binding OpenCV untuk JavaScript/NodeJS versi 3 belum ada.

Jika tidak ada batasan keterpaksaan, maka alasan berikutnya adalah kenyamanan. Beberapa aplikasi bisa ditulis dalam bahasa apapun karena tidak tidak keterpaksaan tertentu. Dalam kasus seperti ini, orang bisa memilih bahasa sesuai dengan familiaritas dengan bahasa tersebut. Sebagian programmer yang menguasai banyak bahasa akan memilih bahasa yang ternyaman (dan kalau bisa yang terbaik) untuk menyelesaikan suatu masalah.

Jangan heran kalau dalam sebagian masalah, C bisa lebih nyaman dari Java atau bahasa lain.  Contoh kecil: sering kali dalam memprogram hardware kita membutuhkan array of bytes (misalnya Protocol Data Unit pada NFC). Inisialisasi array of byte di Java jika nilainya kurang dari 127 bisa dilakukan seperit ini:

byte b [] = new byte[] {1, 127};

Tapi jika nilainya lebih dari 127 tiba-tiba kodenya tidak bisa dicompile:

byte b [] = new byte[] {1, 128};

Dengan error:

incompatible types: possible lossy conversion from int to byte

Cara yang benar adalah dengan menggunakan casting ke byte:

byte b [] = new byte[] {1, (byte)128};

Sedangkan di C, dengan tipe uint8_t (dari header stdint.h) kita tidak perlu memperdulikan hal kecil seperti itu. C juga mendukung bit fields yang bisa membuat manipulasi bit tidak diperlukan (karena dilakukan oleh compiler).

Di sisi lain: membuat aplikasi web lebih sulit dilakukan dengan C. Bereksperimen dengan bilangan integer yang besar (ratusan digit, misalnya untuk operasi RSA) jauh lebih mudah dilakukan di Python dibandingkan Javascript (big integer sudah built in di Python).

Perlu dicatat bahwa bahasa pemrograman yang populer juga masih terus berkembang. Dulu untuk melakukan iterasi list di Java butuh kode yang cukup panjang, tapi kemudian syntax for ditambahkan yang memudahkan ini. Ini hanyalah syntactic sugar alias pemanis saja, di dalamnya implementasinya masih sama. Sebagian bahasa memiliki sintaks yang sudah manis dari sejak dirancang sehingga kadang seseorang lebih memilih bahasa lain.

Kadang tool yang tersedia untuk sebuah bahasa juga menjadi faktor penting dalam memilih sebuah bahasa. Tools ini bisa berupa: compiler, debugger, IDE, dll. Compiler yang lambat bisa membuat frustrasi, jika debugger tidak tersedia akan membuat development lebih lama, IDE yang jelek bisa memperlama coding (apalagi jika sering error/hang) tapi IDE yang bagus bisa mempercepat coding.

Semoga sekarang cukup jelas kenapa ada banyak bahasa, kenapa seseorang perlu mempelajari banyak bahasa, dan kenapa bahasa tertentu dipilih untuk menyelesaikan masalah tertentu.

Bug, Debugging, dan Debugger

Baru saja ada seseorang yang bertanya kepada saya mengenai cara mendebug program buatannya. Sebentar saya merasa heran: masak nggak bisa pake debugger? lalu ketika saya mencoba mengingat-ingat, di sebagian besar buku dan kuliah mahasiswa tidak diajarkan mengenai bug yang umum, cara mencari bug, dan cara menggunakan debugger itu sendiri.

Kemampuan mencari bug di program sendiri ini juga menjadi dasar untuk mencari bug security. Kalo kita bisa menemukan kesalahan yang kita buat sendiri, akan lebih mudah untuk mencari kesalahan di program orang lain.

Bug

Bug adalah segala macam cacat dalam program. Bisa saja cacatnya hanya berupa tampilan yang sedikit salah, bisa crash, bisa berupa bug security (harusnya hanya bisa diakses user X, bisa diakses user Y), kadang bug tertentu tidak muncul sampai kasus ekstreem (misalnya jika jumlah user banyak maka akan out of memory karena ada memory leak).

Sumber bug bisa banyak, dari mulai salah design, salah implementasi, salah konfigurasi, dsb. Sebagai programmer, bug yang akan saya bahas adalah dari sisi implementasi (coding). Biasanya seorang programmer akan belajar sedikit demi sedkit jenis bug dari pengalaman. Semakin banyak coding, semakin banyak salah, semakin banyak belajar.

Beberapa jenis bug sangat umum di semua bahasa (kesalahan logika, kesalahan aritmatika, dsb), tapi bug tertentu hanya muncul di bahasa tertentu atau jika menggunakan framework tertentu. Jadi pengalaman coding tetap merupakan guru yang utama.

Contoh bug yang sederhana adalah lupa menginisialisasi atau mereset variabel. Biasanya jika program berjalan benar pertama kali, lalu ketika diulangi tidak benar hasilnya (dan benar lagi ketika aplikasi direstart) maka penyebabnya adalah lupa mereset variabel.

Contoh lain adalah menggunakan try catch secara malas, misalnya dengan membungkus seluruh fungsi dalam satu try except. Dengan cara ini, maka tidak jelas apa sumber error di sesungguhnya.

Contoh bug yang spesifik terhadap bahasa adalah bug manajemen memori di C. Kesalahan mengakses memori di C sangat mudah terjadi dan biasanya akan menyebabkan crash.

Source Control

Jangan heran juga kalau kadang bug baru muncul karena hal sepele, misalnya source code berubah  karena keyboard tersenggol. Msalnya sebuah konstanta 1000 terdelete angka nol terakhirnya (atau bertambah satu), atau tanda “lebih besar sama dengan” terhapus  menjadi lebih besar saja. Di sini penggunakan version control (yang populer saat ini: Git) sangat berguna, Anda bisa mereview segala perubahan pada source code.

Source control juga memungkinkan kita melihat sejarah perubahan secara keseluruhan. Bagi security researcher, ini sering menjadi ladang untuk mencari bug baru di software open source. Jika ada yang menambahkan fungsionalitas baru, maka kemungkinan ada bug baru yang muncul.

Unit Testing

Mencari dan membetulkan bug itu susah (baik bug sendiri maupun orang lain), jadi hal pertama yang perlu dicoba adalah: menghindari bug. Hal yang paling dasar adalah: kita perlu memecah program kita menjadi unit yang kecil (unit di sini berupa fungsi/kelas/method) dan menguji tiap bagian kecil tersebut. Istilahnya untuk ini adalah unit testing. Kita bisa menggunakan library tertentu untuk unit testing, atau panggil saja fungsi yang akan ditest.

Saya akan mengasumsikan Anda minimal sudah bisa membuat aplikasi yang bisa dicompile dan bisa dijalankan. Jika Anda masih salah syntax, salah opsi untuk mengcompile, dsb, sebaiknya ada mulai lagi dari nol dan mulai perlahan.

Dengan memecah program menjadi unit kecil dan mengujinya satu persatu, maka kesalahan umumnya bisa dilokalisasi: fungsi X ini masih salah. Pertanyaan berikutnya adalah: apa salahnya?

Asersi

Saat ini kebanyakan bahasa memiliki fitur assert. Fitur ini memungkinkan kita melakukan pengecekan ekstra (yang biasanya tidak akan dilakukan di versi produksi). Assert ini biasanya digunakan untuk menyatakan kondisi yang pasti harus benar, karena jika tidak benar maka titik program berikutnya akan error fatal.

Ini adalah contohnya:

assert(index >= 0);

val = values[index];

Jika index kurang dari 0, maka ada sesuatu kesalahan fatal di program kita (mungkin kesalahan logika, mungkin ada hal yang lupa ditangani). Jika asersi diaktifkan biasanya program akan berhenti dengan “Assertion error”.

Di berbagai bahasa assert ini bisa diaktifkan/nonaktifkan dengan opsi tertentu. Jadi dalam versi rilis kita bisa membuang berbagai pengecekan asersi ini.

Pesan dari Compiler dan Linter

Sebelum melihat jauh ke mana-mana, coba lihat dulu apakah ada warning dari compiler Anda. Contohnya untuk potongan kode C ini:

 int i;
 printf("i = %d\n", i);

Compiler memberitahu:

warning: ‘i’ is used uninitialized in this function [-Wuninitialized]

Bacalah pesan error dan warning dengan teliti. Di situ dijelaskan bahwa variabel i tidak diinisialisasi. Di C, variabel lokal nilainya tidak bisa diprediksi jika tidak diinisialisasi.

Selain compiler, biasanya ada program yang namanya linter untuk sebuah bahasa yang bisa memberi peringatan jika ada sesuatu yang dianggap tidak standar atau aneh. Anda bisa melihat daftar lengkap software semacam ini di Wikipedia. Sebagian software ini mudah sekali diinstall, dan sebagian lagi terlalu rumit, tapi beberapa IDE sudah memiliki linter built in. Saran saya: jika Anda masih belajar dan tools linter tersedia, pakailah dan perhatikan outputnya, jika terlalu sulit mensetupnya ya sudah lupakan saja untuk saat ini.

Print debugging

Lalu berikutnya cara paling primitif dalam debugging adalah dengan menuliskan nilai saat ini menggunakan: “print” “echo”, “printf” atau sejenisnya.

Contoh sederhana, misalnya kita punya conditional di Python seperti ini (melakukan regular expression matching):

if (re.search(PATTERN, x)): # do something

Lalu bagian aksi tidak pernah dieksekusi, atau cuma dieksekusi beberapa kali. Apakah Anda yakin patternnya benar? Coba print sebelumnya, jangan-jangan regexnya masih salah untuk input tertentu:

print "Input ", x, "Match result ", re.search(PATTERN, x)

Tentunya tidak semua aplikasi bisa punya layar yang menampilkan teks itu (contohnya Game, atau aplikasi grafik lain). Biasanya cara yang lebih baik adalah menggunakan library untuk logging yang saat ini sudah built in di banyak bahasa (misalnya ada modul logger di Python, java.util.logging di Java, dsb). Output logging bisa dikonfigurasi sedetail apa, dan outputnya ke mana (ke file, ke terminal, ke jaringan, dsb).

Logging tidak hanya untuk proses development. Banyak aplikasi menyediakan fungsi logging untuk mencatat berbagai hal yang berhubungan dengan aplikasi untuk mendebug jika ada masalah ketika dijalankan. Contohnya aplikasi bisa menampilkan di lognya: “berusaha melakukan koneksi database ke server XX port YY dengan username ZZ”, yang bisa diikuti dengan “Koneksi berhasil”, atau “Koneksi Gagal, pesan error: invalid username or password”.

Debugger

Debugger adalah tools untuk mencari bug. Di kebanyakan IDE (Integrated Development Environment), tools ini sudah built in dan mudah dipakai. Ada juga debugger stand alone, tapi biasanya ini lebih sulit bagi pemula.

Untuk menggunakan debugger pertama kita perlu mengeset breakpoint, yaitu titik berhenti sementara (break). Ketika kita mengklik “debug” maka debugger akan mulai menjalankan program sampai titik itu. Di beberapa bahasa, jika kita tidak mengeset breakpoint, maka program dihentikan sementara di titik awal.

Debugger paling dasar sekalipun akan memiliki fungsi untuk menampilkan nilai variabel saat ini. Dengan menggunakan ini kita biasanya tidak perlu mencetak dengan printf, tapi untuk mencetak objek yang kompleks, kadang tetap saja keluaran print masih lebih baik.

Fungsi debugger berikutnya adalah melakukan single stepping, artinya kita bisa menelusuri langkah demi langkah program. Contohnya jika kita memiliki source sederhana

diskon = 0.1

harga = 10000

harga = harga - (diskon * harga)

Kita bisa melakukan single step dan melihat nilai diskon dan harga di setiap langkah.

contoh

Jika kita memanggil fungsi lain, maka kita memiliki dua opsi, masuk ke dalam fungsi itu (istilahnya biasanya “step into”) atau memanggil fungsi itu, lalu segera meneruskan ke baris berikutnya (kita tidak peduli atau tidak ingin mendebug fungsi itu, istilah ini “step over”).

Jika fungsi yang akan kita cek sangat jauh atau hanya dipanggil di kondisi tertentu maka kita bisa menggunakan breakpoint. Biasanya di berbagai IDE ini bisa dilakukan dengan mengklik di samping nomor baris, dan akan muncul bulatan merah. Jika kita menekan tombol “continue”, maka program akan dijalankan dan akan dihentikan sementara di titik breakpoint tersebut.

Ada juga yang namanya “conditional breakpoint”. Artinya kita akan berhenti hanya pada kondisi tertentu. Misalnya kita ingin berhenti dalam loop setelah i > 100, karena di titik itu ada data yang aneh, maka kita bisa menambahkan kondiri “i>100”

conditional

Beberapa debugger memiliki fungsi yang menakjubkan, misalnya GDB mendukung reverse execution dan Visual Studio mendukung “Edit and Continue”. Untuk perubahan kecil, kita bisa mengubah program kita tanpa menghentikan debugger.

Di beberapa environment mensetup debugging tidak mudah, tapi ketika sudah terinstall ini akan sangat berguna sekali.

Debugger level Assembly

Untuk program biasa, Anda biasanya tidak akan pernah butuh mendebug sampai level ini, tapi jika Anda membuat eksploit atau berusaha mengeksploit binary, Anda perlu tahu ini (saya pernah membuat pengantar mengenai buffer overflow jika Anda tertarik).

Debugger di level assembly sebenarnya tidak berbeda jauh dari level source code. Jika kita punya source codenya, bahkan kita bisa melihat keduanya berdampingan. Di level assembly kita bisa menelusuri tiap instruksi dan juga melihat nilai register. Dengan melihat nilai register beserta flagsnya Anda bisa belajar banyak mengenai assembly.

Tools lain

Kadang debugger saja tidak cukup, tools analisis runtime seperti strace, ltrace, valgrind dsb akan berguna membantu menemukan bug terutama di kode native. Topik mengenai tools sudah pernah saya bahas sebelumnya.

Logika

Tools apapun tidak akan bisa membantu jika kita tidak punya logika yang baik. Dasar dari debugging adalah mencari kesalahan program, lalu membetulkannya agar berjalan sesuai harapan. Jadi di tahap paling awal, Anda sendiri harus tahu harapannya apa yang terjadi di setiap langkah.

Contohnya jika Anda mendebug algoritma mencari nilai maksimum, Anda perlu mengerti dulu seperti apa seharusnya algoritmanya dan apakah ketika dijalankan sudah sesuai harapan.  Dalam kasus ini, di langkah pertama seharusnya nilai maksimum adalah elemen pertama, di langkah kedua, jika nilainya lebih besar maka elemen ini yang jadi elemen maksimum (dan jika tidak, maka elemen pertama yang tetap menjadi maksimum), dan seterusnya untuk elemen berikutnya.

Penutup

Sebenarnya bisa panjang sekali bahasan mengenai bug software, artikel ini hanya sekedar perkenalan. Anda sebaiknya mendalami berbagai tools supaya lebih produktif dalam bekerja, dari mulai tools source control, editor, debugger, linter, build system (Makefile, CMake, Ant, Maven, atau apapun), maupun tools lainnya.

Untuk Anda yang baru belajar memprogram: jika Anda menggunakan IDE, sesekali tekanlah tombol debug (atau menu debug) dan cobalah bereksperimen menggunakan fungsi dasar seperti step into, step over, dsb. Ini akan sangat membantu Anda dalam belajar pemrograman.

 

 

Masuk Dunia Software Development

2016-03-07 (6)

Banyak orang yang ingin memasuki dunia software development, dan bertanya ke saya: saya perlu belajar bahasa/teknologi yang mana saat ini? Ada yang sudah kerja di IT lalu ingin masuk software development (ada yang di departemen IT, ada yang jaga warnet, dsb). Ada juga anak SMU yang nanya bahasa dan teknologi apa yang perlu dipelajari duluan, dsb. Di sini saya akan berusaha membahas pendekatan pembelajaran yang mungkin, dan sekilas teknologi yang ada saat ini dan kelemahan/kelebihannya dari sudut pandang pemula.

Hal pertama yang perlu Anda pikirkan adalah: apa motivasi Anda? ada yang karena ingin uang lebih karena membuat aplikasi bisa menghasilkan uang banyak, atau Anda ingin sekedar berkontribusi untuk opensource (yang dasar motivasinya juga banyak). Motivasi ini biasanya akan menentukan jalan apa yang bisa dipilih untuk menjadi developer.

Saya dan teman-teman saya dari tempat kuliah (informatika ITB) memiliki kelebihan karena dipandang “pintar”, dan pasti bisa belajar teknologi apapun (dan biasanya memang begitu karena sudah diajari dasar berbagai macam hal ketika kuliah). Dari tempat kami pertama bekerja, ada yang mendalami dan menjadi ahli di bidang yang spesifik (misalnya telekomunikasi, atau enterprise development), ada juga yang bosan dan berpindah bidang. Jadi bagi kami tidak ada kewajiban untuk memilih apakah perlu belajar Java dulu atau PHP dulu, lalu mencari kerja yang sesuai. Untuk kebanyakan orang lain, tentunya pendekatan tersebut biasanya tidak berlaku, tapi ada beberapa pendekatan lain yang mungkin.

Inti dari pendekatan untuk masuk dunia sofware development adalah membuat sofware. Tentunya sulit mencari kerja tanpa pengalaman. Jadi bagaimana mencari pengalaman tanpa bekerja di sebuah software house atau menerima proyek sebagai freelancer?

Pendekatan pertama yang saya lihat adalah melalui dunia opensource. Salah satu orang terkenal adalah Con Kolivas, seorang ahli anastesi, yang tidak punya background computer science, tapi sangat tertarik pada linux dan menjadi developer kernel Linux. Tentunya kecerdasan dan dedikasi orang tersebut luar biasa, tapi tidak perlu kontribusi ke proyek yang sangat high profile untuk bisa masuk melalui dunia opensource. Cara yang paling sederhana adalah dengan membuat plugin untuk berbagai proyek open source, seperti misalnya wordpress, joomla, dan berbagai software lain. Membuat plugin tidak melibatkan proyek utama, jadi mudah dilakukan. Jika sudah cukup confident, Anda juga bisa mengirimkan patch/pull request untuk proyek utama.

Pendekatan berikutnya adalah membuat app sendiri untuk dipublish melalui dunia app store. Ketika masih demam app store, banyak orang nekat terjun membeli buku atau mengambil kursus untuk memprogram iOS atau Android. Sebagian dari mereka sangat berhasil dan menjadi jutawan (dalam USD), dan sebagian gagal. Tapi pendekatan ini bisa berhasil karena: kita bisa membuat aplikasi yang kita mau, tidak dibatasi waktu, dan ada targetnya (menjual app).

Jika Anda ingin membuat aplikasi web, maka pendekatan di atas bisa diganti dengan membuat web app sendiri. Terserah Anda jenis web yang ingin Anda buat seperti apa. Anda juga bisa mencari teman yang bisnis online dan mencoba membantu membuatkan web app untuk teman tersebut.

Pendekatan lainnya, yang menurut saya agak berisiko adalah dengan nekat belajar teknologi tertentu saja, dan berusaha mencari pekerjaan yang berhubungan dengan teknologi tersebut. Anda bisa meyakinkan orang bahwa Anda mengenal teknologi tertentu dan mengambil proyek freelance sesuai teknologi tersebut, atau berusaha mengambil sertifikasi khusus teknologi tertentu (misalnya Java atau .NET) dan berusaha langsung mencari kerja dengan menggunakan sertifikasi itu.

Anda bisa melihat di posisi Anda saat ini apa yang bisa Anda gali untuk memulai. Mungkin Anda masih SMU jadi tahu apa kebutuhan anak-anak SMU dan bisa membuat app yang sesuai. Mungkin Anda bekerja di perusahaan tertentu dan bisa melihat app apa yang bisa dikembangkan untuk perusahaan jenis itu.

Memilih teknologi yang dipelajari adalah hal yang sulit: teknologi berkembang sangat cepat meski dasarnya masih sama. Saya ambil contoh teknologi Java. Teknologi ini ada sejak pertengahan 1990an, dan masih ada dan dipakai sampai sekarang. Tapi teknologi Java (meliputi bahasa, API, runtime environment) sudah berubah banyak. Berbagai fitur bahasa Java ditambahkan setiap kali versi major baru dirillis. Berbagai framework dan tools muncul dan dan mati bergantian. Untuk mengcompile saja ada beberapa pendekatan (manual, ant, maven, gradle), ada berbagai framework sisi server yang selalu silih berganti (struts, spring, grails, dan puluhan lain yang tidak saya ingat), belum lagi berbagai library yang perlu dikuasai, misalnya library apa untuk membuat PDF, library apa untuk memproses gambar, dan berbagai library lain. Belajar bahasa Java saja tidak cukup untuk membuat kebanyakan aplikasi real world, kita tetap perlu belajar framework, library, dan tools yang spesifik untuk aplikasi tersebut.

Penjelasan di atas hanya untuk memberi gambaran bahwa belajar bahasa saja tidak cukup, itu hanya awalnya saja. Hal yang penting ketika mempelajari sebuah bahasa adalah benar-benar memahami fitur-fiturnya, supaya tidak bingung ketika fitur itu dipakai di framework atau library tertentu.

Sekarang saya akan bahas beberapa teknologi dasar yang menurut saya perlu diketahui, lalu berikutnya berbagai teknologi yang bisa Anda pilih, sesuai dengan keadaan Anda.

Teknologi dasar pertama adalah SQL. Ini bisa dipelajari terpisah dari bahasa manapun. Semua aplikasi butuh penyimpanan, dan meskipun teknologi NoSQL mulai banyak dipakai, tapi SQL masih digunakan di mana-mana. Aplikasi server memakai berbagai DBMS (Misalnya SQL Server, MySql, Posgres), aplikasi mobile memakai SQLite, bahkan aplikasi browser bisa memakai WebSQL (saat ini disupport oleh Chrome, Safari, Opera).

Teknologi berikutnya adalah HTML/CSS dan JavaScript. HTML dan CSS dasar diperlukan karena banyak sekali user interface dibuat berdasarkan HTML/CSS. Aplikasi web tentunya memakai teknologi itu, tapi banyak app di desktop dan app store juga memakai HTML/CSS untuk user interfacenya. Mengenal javascript juga akan sangat berguna untuk membuat web yang interaktif, dan bahkan sekarang JavaScript juga bisa dipakai memprogram sisi server dengan NodeJS. Salah satu hal praktis yang bisa dibuat dengan HTML/CSS/JS adalah dengan membuat extension untuk browser (contoh extension browser yang terkenal adalah AdBlock).

Jangan lupa pelajari berbagai tools yang ada, terutama command line yang bisa dipanggil program lain. Ini akan sangat berguna untuk mengurangi pekerjaan memprogram. Anda bisa menulis beberapa ribu baris untuk meresize berbagai format gambar, tapi Anda bisa lebih gampang memanggil program imagemagick dari dalam program Anda untuk melakukannya dengan satu baris saja. 

Setelah itu Anda bisa memilih salah satu teknologi utama yang ingin Anda kuasai. Misalnya Anda bisa mendalami teknologi .NET (bisa melalui berbagai bahasa .NET misalnya C# atau Visual Basic .NET). Teknologi .NET saat ini cukup banyak dipakai di berbagai perusahaan besar. Teknologi ini sangat Microsoft centric, walau sekarang mulai dibuka sourcenya agar disupport di platform lain. Dari pengamatan saya, untuk teknologi Web tidak banyak perusahaan menengah atau kecil yang memakai .NET. Jika Anda memprogram aplikasi desktop untuk Windows, maka .NET merupakan pilihan yang bagus. Teknologi .NET bisa juga dipakai untuk memprogram mobile, terutama Windows Phone. Ada juga tools tambahan yang memungkinkan kita membuat program .NET yang jalan di Android ataupun iOS, tapi saya lebih menyarankan Anda memakai Java untuk Android dan Objective C atau Swift untuk iOS.

Alternatif teknologi .NET adalah Java. Java bisa dipakai untuk memprogram aplikasi desktop, mobile (Android), dan Web (Java 2 EE dengan berbagai teknologi dan framework yang ada). Cukup banyak juga enterprise yang memakai Java, apalagi karena Java ini bisa dideploy di berbagai OS, termasuk Linux (yang biaya lisensinya gratis). Dari pengamatan saya: bebereapa perusahaan besar memakai lebih dari satu teknologi (misalnya Java dan .NET sekaligus), karena mereka tidak ingin ditekan oleh vendor tertentu (kalau vendor berusaha menjual harga mahal, maka bisa bilang: saya switch aja deh ke teknologi yang satu lagi).

Anda bahkan bisa menjadikan HTML/JS/CSS menjadi teknologi utama Anda karena sekarang semua jenis aplikasi bisa diprogram dengan HTML/JS. Anda bisa membuat mobile app dengan Phonegap/Cordova, bisa membuat web app dengan menggunakan nodejs di sisi server.

Di sisi open source, ada berbagai alternatif. Yang saya maksud dengan open source di sini adalah open source yang tidak didukung perusahaan besar (Java dan .NET sekarang sudah open source juga). Teknologi PHP masih dipakai diberbagai perusahaan besar (misalnya facebook), tapi sekarang sebagian besar sudah diprogram menggunakan framework tertentu (Larave, CodeIgniter, Nette, dan ratusan framework lain), tidak seperti dulu di mana orang memprogram langsung PHP prosedural tanpa framework.

Meski di luar negeri sudah sangat populer, sepanjang pengetahuan saya penggunaan teknologi Python, Ruby dan lain-lain masih kurang di Indonesia. Mungkin karena tidak ada vendor tertentu yang berusaha menjual produk ke perusahaan (tidak seperti Java atau .NET) sehingga ini masih kurang populer. Jika Anda mau mengambil berbagai pekerjaan freelance dari luar negeri.

Jika Anda spesifik ingin membuat aplikasi iOS, maka sebaiknya Anda belajar Objective C atau Swift. Bahasa Swift lebih sederhana, tapi masih sangat berkembang (terutama sepanjang tahun lalu). Bahasa Swift ini cukup sederhana, tapi sangat Apple centric, dan ilmunya tidak berlaku untuk platform lain.

Selagi belajar teknologi tersebut, Anda sebaiknya belajar berbagai macam hal yang berhubungan dengan development, misalnya versioning (sekarang yang populer menggunakan Git), testing (tergantung teknologi apa yang Anda pakai), deployment (misalnya dengan docker), tools untuk setup development (misalnya dengan Vagrant), IDE (tergantung bahasa yang ingin dipakai). Teknologi-teknologi ini adalah pelengkap yang penting dipelajari, dan lebih mudah dipelajari sambil praktik.

Pertanyaan berikutnya adalah bagaimana cara belajarnya? Anda bisa membeli buku lalu membacanya (silakan dibandingkan sendiri, karena buku yang dianggap bagus oleh satu orang dianggap jelek oleh orang lain), Anda juga bisa mengambil kursus online baik di Coursera, EDX, Udemy, maupun yang lain. Jika Anda suka pendekatan video, banyak sekali tutorial gratis di youtube.

Setelah yakin dengan kemampuan Anda, Anda juga bisa mengambil berbagai sertifikasi. Saya sendiri tidak pernah mengambil sertifikasi pemrograman, jadi kurang tahu bagaimana pandangan perusahaan terhadap berbagai sertifikasi yang ada.

Keahlian yang paling dibutuhkan dalam memprogram adalah mencari jawaban atas error yang ditemui. Keahlian Anda mencari dengan Google akan sangat berguna. Situs stack overflow juga akan sangat membantu dalam menjawab berbagai pertanyaan Anda. Satu hal yang penting adalah: pahami berbagai istilah yang ada, ini akan sangat memudahkan ketika Anda mencari sesuatu menggunakan search engine.

Selamat memasuki dunia development software.

Programming dan Penetration Testing

Pentest adalah kegiatan menyerang sistem komputer untuk mencari kelemahan security, atau dari Wikipedia:

A penetration test, or the short form pentest, is an attack on a computer system with the intention of finding security weaknesses, potentially gaining access to it, its functionality and data.

Pentesting dilakukan atas permintaan client, jadi bukan hacking ke sembarang website. Contoh sederhana pentesting seperti ini: coba jebol website perusahaan kami, apakah ada bug securitinya? atau: coba pergi ke lobi atau tempat parkir perusahaan kami, apakah ada WIFI terbuka, apakah dari situ bisa masuk ke sistem internal perusahaan kami?. Kami punya app mobile, apakah bisa “dijebol” (misalnya apakah kita bisa membuat request ke server supaya memberikan data user lain).

Karena ini blog mengenai programming, saya tidak akan membahas banyak mengenai pentesting, hanya ingin menunjukkan betapa keahlian programming bisa sangat berguna untuk pentesting. Dari contoh yang saya sebutkan di atas, scope dari pentesting bisa sangat banyak, mulai dari yang on site: datang dan mengecek kabel, wireless network, dsb, sampai ke level network dan aplikasi (baik web, desktop, mobile). Saya hanya ingin membahas aspek programming, untuk mendorong peminat bidang security agar mau belajar programming.

Perkiraan saya mungkin sekitar 70% pekerjaan pentesting bisa dilakukan dengan tools yang sudah tersedia, baik yang open source maupun komersial, tanpa butuh keahlian scripting ataupun programming. Sisanya bakal butuh programming. Bahkan saya yakin 100% beberapa jenis bug tidak bisa ditemukan tanpa keahlian programming.

Screenshot_2014-11-27-18-19-36

Kemampuan programming minimal yang dibutuhkan adalah bisa mengcompile atau menjalankan program dalam berbagai bahasa. Kadang di sebuah server tidak tersedia tool tertentu, jadi kita perlu mengcompile dari source karena OS di server itu sudah terlalu lama (misalnya masih banyak yang memakai RHEL 4). Jika tidak tahu bagaimana menjalankan sesuatu, maka sudah game over di titik ini. Pernah saya baca di blog pak Budi Rahardjo mengenai kompetisi CDC (Cyber Defense Competition):

Salah satu soal yang disampaikan adalah men-decode data base64 yang kemudian menjadi skrip Python, yang tinggal dijalankan. Lucunya ada banyak yang gak tahu Python. ha ha ha. Mereka kebingungan menjalankannya. Padahal tinggal “python namaskrip.py”. Mereka tidak perlu tahu bahasanya. hi hi hi. Ada yang pura-pura tahu dan me-rename menjadi bahasa C, menambahkan “#include ” dibagian awalnya, kemudian mencoba compile. Ya gak bakalan jalanlah. he he he.

Kejadian semacam di atas itu yang mendorong saya menulis tulisan seperti ini.

Keahlian lain adalah mencari program atau menulis program kecil dalam bahasa tertentu yang kadang tidak terlalu umum atau sudah kuno. Contoh: jika sebuah web server bisa menerima upload file, dan web server itu hanya bisa menjalankan ASP versi klasik, ya kita harus bisa mencari shell dalam ASP Classic (bukan ASP.NET). Berbeda dengan software development biasa di mana kita bisa memilih bahasa pemrograman atau teknologi yang ingin kita pakai, di sini kita dipaksa mengikuti apa yang tersetup di server.

Jika beruntung, sudah ada orang yang menuliskan program standar (web shell) yang memiliki fungsi seperti “file manager/file upload” (untuk mengupload tool tambahan), “shell” (untuk mengeksekusi command apapun di sisi server), dan “database shell” (untuk mengirimkan query apapun ke database). Jika tidak beruntung, atau ada batasan tertentu di server, mungkin kita perlu membuat tool baru. Contoh sederhana: jika server membatasi upload hanya 100 KB saja, sementara binary nmap yang ingin diupload (plus librarnya) besarnya beberapa megabyte, maka kita perlu membuat program kecil untuk mengupload parsial lalu menggabungkan hasil uploadnya.

Keahlian membaca kode dalam berbagai bahasa juga diperlukan. Dalam beberapa kasus, kita bisa mendapatkan akses ke source code aplikasi web (karena bug, karena salah konfigurasi, karena lupa ikut mengupload direktori “.git”, dsb). Setelah punya source code, kita bisa menemukan bug tambahan dengan membaca kodenya. Sebagai pentester, tentunya Anda tidak akan bilang: wah ternyata dia pake Python, saya nggak tau cara ngehack aplikasi web dengan Python.

Dengan membaca source code, hal paling minimal adalah mengerti di mana file konfigurasi supaya bisa mengekstrasi user/password database, berikutnya adalah mencari bug-bug tambahan seperti SQL Injection, hidden functionality, dsb.

Dengan maraknya OS Mobile, sekarang pentesting juga masuk ke ranah mobile. Di sini ilmu reverse engineering sangat diperlukan. Untuk OS Android, reverse engineering bisa dilakukan dengan decompiler yang bisa mengembalikan kode Java ke bentuk semula (kecuali sudah diobfuscate), jadi kembali keahlian membaca kode diperlukan.

Setelah mengetahui kodenya, biasanya kita perlu melakukan fuzzing request, alias mencoba-coba berbagai kemungkinan request. Untuk aplikasi berbasis HTTP, kita masih bisa memakai proxy (misalnya ZAP) dan mengubah-ubah request untuk tahu reaksi server (bagaimana jika nilaiya negatif, bagaimana jika nama file mengandung “../”, dsb). Tapi untuk aplikasi yang memakai protokol khusus via SSL, kita perlu memahami, lalu mengimplementasikan ulang client sendiri yang bisa melakukan fuzzing.

Pengetahuan mengenai best practice dalam sebuah bahasa juga diperlukan dalam membuat aplikasi yang aman. Contoh: untuk menghasilkan bilangan random untuk kriptografi di Java gunakan SecureRandom (jangan Random). Di Android untuk melakukan koneksi SSL menggunakan socket, jangan gunakan SSLFactory tapi gunakan SSLCertificateSocketFactory, dsb. Pekerjaan pentester cukup mudah di sini, hanya menyarankan saja, dan programmer yang akan mengimplementasikan saran tersebut.

Saya sudah banyak menemukan bug yang memerlukan banyak coding. Ada bug yang terkait dengan penyimpanan password (terenkripsi) yang disimpan lokal di device yang seharusnya aman, tapi ternyata saya bisa membuat tool yang cukup optimal untuk bisa mengcrack dalam 1 jam karena banyak hal kecil yang lupa dilakukan oleh programmer (lupa menginisialisasi IV, memakai EBC). Saya pernah menemukan bug fatal yang berhubungan dengan menggunakan algoritma hashing yang tidak aman (tidak memakai Cryptographic Hash Function). Dengan tools yang tersedia saja, tanpa pengetahuan programming (dan kriptografi), kedua bug itu tidak akan bisa ditemukan.

Jadi saran saya: untuk mereka yang tertarik di bidang security, pelajari juga bagian programmingnya. Ini saya masih bicara level pentesting yang kebutuhkan programmingnya masih minimal. Di bagian lagin security, keahlian programming lebih dibutuhkan lagi, misalnya membuat exploit butuh pemahaman yang lebih mendalam tentang sistem dan low level programming.

Dalam full security audit, selain pentesting kadang client menginginkan juga review kode mereka, jadi kita perlu bisa membaca, menjalankan, dan memberi saran yang berkaitan dengan security.

Buat saya sendiri sebagai programmer, saya jadi rajin membaca mengenai best security practice untuk berbagai bahasa dan framework. Jika ada yang bertanya: buat apa sih belajar bahasa X atau teknologi Y, saya bisa bilang: mungkin suatu saat ada sistem yang memakai teknologi itu yang perlu saya test.

Menjual Aplikasi di Appstore

Dulu waktu saya masih kuliah, menjual aplikasi tidaklah semudah sekarang. Waktu saya kuliah, pemrograman mobile masih cukup baru. Menjual aplikasi baik desktop maupun mobile juga tidak mudah (sekarang berbagai metode pembayaran sudah tersedia). Biasanya yang saya kerjakan adalah mencari proyek.

playstore

Saya punya saran bagi mahasiswa yang saat ini masih kuliah: cobalah membuat aplikasi, minimal satu dan menjualnya di sebuah application store. Mengapa saya menyarankan orang menjual aplikasi di sana? Tujuan utamanya adalah untuk belajar. Menurut saya ada banyak sekali yang bisa dipelajari dari menjual aplikasi di app store. Pelajaran ini bukan cuma dari sisi programming, tapi keseluruhan software development lifecycle.

Catatan: Biasanya orang-orang mengasosiasikan “App Store” dengan apple, dalam konteks artikel ini “App Store” adalah sembarang application store (misalnya Apple App Store, Nokia OVI, BlackBerry Appworld, Google Play, dsb).

Sejak “demam app store” banyak orang (termasuk non programmer) yang belajar memprogram dan berusaha membuat aplikasi yang laris agar menjadi jutawan. Memang mungkin menjadi jutawan dengan menjual aplikasi, tapi saran saya: jangan jadikan itu tolok ukur kesuksesan. Anda bisa tetap sukses belajar meskipun tidak menjadi jutawan dari appstore.

Apa saja yang bisa dipelajari dari menjual aplikasi di app store? pertama dari sisi programming: Anda belajar bagaimana memoles dan mempaketkan aplikasi supaya bisa dijual. Anda akan belajar membuat aplikasi yang layak pakai oleh end user. Kadang untuk proyek tertentu (misalnya proyek pemerintah), aplikasi yang dibuat asal jadi, asal memenuhi spesifikasi.

Ketika Anda punya pengguna, Anda akan belajar bagaimana berinteraksi dengan pengguna. Anda akan menghadapi bug report, feature request, pujian, dan juga cacian. Bahkan jika Anda membuat game yang amat bagus sekalipun, bisa ada yang protes dan memberi review 1 bintang karena mereka “stuck di level 5”. Jika aplikasi Anda cukup kompleks, akan ada bug yang hanya muncul di user tertentu, dan Anda belajar mendebug bersama pengguna aplikasi Anda.

Setelah ada perbaikan, Anda akan bisa merilis update software Anda (meluncurkan versi baru). Setelah Anda merilis beberapa versi, Anda akan sadar perlunya memakai versioning system. Bagi Anda yang belum memakai versioning system (Git, CVS, dsb), maka ini saat yang baik untuk belajar.

Setelah merilis aplikasi, jangan berhenti dan menunggu. Belajarlah mempromosikannya. Pertama: buatlah website untuk aplikasi Anda, bisa berupa halaman blog, atau mungkin Facebook page. Anda perlu belajar membuat teks dan screenshot yang menarik dan bahkan mungkin perlu membuat video. Setelah itu promosikan di media sosial seperti Twitter dan Facebook. Hubungi juga situs-situs komunitas dan mailing list komunitas. Anda akan belajar bagaimana mengirim email mempromosikan produk Anda.

Di titik ini Anda bisa mengetahui apakah Anda tertarik pada marketing atau tidak. Anda mungkin akan bereksperimen dengan harga yang berbeda, bereksperimen menggunakan iklan, menggunakan in app purchase, dan sebagainya. Jika Anda membuat aplikasi bagus, memasarkan dengan baik, dan beruntung, Anda bisa mendapatkan pendapatan lumayan dari app store ini dari mulai sekedar puluhan ribu rupiah sampai puluhan juta tiap bulannya.

Saya menambahkan kata “beruntung” karena kadang memang butuh keberuntungan supaya aplikasi sukses di pasaran. Kata “beruntung” juga sebagai penghibur bahwa kadang-kadang aplikasi yang sudah sangat bagus dan dipasarkan dengan mati-matian masih bisa gagal di appstore. Sedangkan aplikasi sangat sederhana kadang bisa sangat sukses. Jadi kadang bukan kesalahan pembuat aplikasi dan bukan kesalahan marketing. Bisa saja di saat yang bersamaan, ada aplikasi serupa yang sedang dipasarkan perusahaan yang lebih besar.

Tergantung app store mana yang Anda pilih, Anda mungkin harus menandatangani perjanjian tertentu. Anda akan belajar mengenai revenue sharing, pajak, sistem pembayaran, dsb. Anda akan belajar bahwa ada app store yang harganya sama di seluruh dunia (misalnya harga aplikasi 0.99 USD akan sama di manapun juga di dunia), tapi ada juga yang memvariasikan harga tergantung wilayah pembeli (misalnya: di Nokia Ovi Store harga 0.99 EURO di Eropa bisa menjadi 0.3 USD di India).

Sebagai perbandingan: mencari proyek software itu gampang-gampang susah, baik dari proses mencari, mengerjakan, sampai mengejar pembayarannya. Appstore itu sangat gampang: Anda bisa masuk ke app store dengan gratis (misal Blackberry), sekali bayar (25 USD untuk Google Play), atau per tahun (99 USD/tahun, Apple AppStore). Anda bisa langsung menjual app dengan mudah, tidak ada yang memburu deadline, pembayaran juga langsung masuk rekening (tidak perlu menagih).

Selain mendapatkan pengalaman, Andaikan tidak ada yang membeli aplikasi Anda, Anda tetap memiliki portfolio. Sudah banyak sekali penawaran pekerjaan dan proyek yang saya terima karena ada orang yang melihat aplikasi yang saya buat. Ini cukup wajar. Misalnya ada seseorang yang ingin membuat aplikasi resep masakan, mereka akan mencari orang yang sudah pernah membuat aplikasi sejenis itu.

Saya sendiri kurang sukses secara langsung dari appstore, tapi cukup banyak mendapat tawaran proyek karena aplikasi yang saya pajang di appstore. Walau demikian, secara langsung dari appstore ada pendapatan ekstra belasan sampai puluhan dollar sebulan yang cukup untuk membayar hosting, atau kadang-kadang membeli satu dua barang online untuk dioprek. Dapet 5 USD? cukup buat beli Arduino atau makan siang yang enak, 35 USD? bisa beli Raspberry Pi, atau duitnya bisa juga dipinjamkan jika tidak tau ingin diapakan.