15 Feb 2007

‘Mengamankan’ Kode dengan Obfuscator, perlukah?


Perlukah melindungi kode perangkat lunak yang kita buat dari jamahan pihak lain?
Beragam pendapat akan terlontar untuk membahas masalah ini. Satu pendapat mungkin mengatakan perlu, karena itu adalah kekayaan intelektual dan kita berhak melindunginya.
Dan bagi vendor/pengembang perangkat lunak yang telah menginvestasikan biaya, tenaga dan pikiran untuk membuat kode tersebut tidak rela kode yang dibuatnya dijamah (dibaca) oleh orang lain.


Pendapat lain mengatakan tidak perlu, mereka berargumen kode hanyalah hasil dari sebuah proses pengembangan perangkat lunak dan nilai terbesar dari keduanya adalah proses. Orang yang membaca kode program tidak mengalami proses yang sama  dengan yang membuat kode asal, sehingga kode hanyalah cuplikan kecil dari suatu nilai yang berharga.


Pandangan saya terhadap pertanyaan di atas lebih cenderung ke pendapat kedua. Pendapat pertama lebih terpengaruh oleh kaptialisme dimana semuanya dianggap ‘modal’ dan ‘milik saya’, orang lain yang ingin menjamah (membaca, memakai dan mengeksekusi kode) harus memberikan imbal balik terlebih dahulu yang tentu saja berupa ‘modal’ (materi atau uang). Anda bayar, Anda dapat.


Dalam semangat berbagi, tolong-menolong dan maju bersama, pendapat kedua adalah yang paling sesuai. Biarkanlah kode dibaca orang lain, toh ‘experience’ yang kita peroleh belum tentu dirasakan oleh orang lain tersebut.



Bukankah ilmu kita bertambah dengan berbagi ilmu?

13 Feb 2007

Oracle Package untuk fungsi ‘terbilang’ (repost)

Contoh penggunaan:
  1. SELECT PKG_DIGIT_SPELLER.ENGRupiah('12345') FROM DUAL
  2. SELECT PKG_DIGIT_SPELLER.ENGRupiah('12345.56') FROM DUAL
Hasil:
  1. TWELVE THOUSAND THREE HUNDRED AND FOURTY-FIVE RUPIAHS
  2. TWELVE THOUSAND THREE HUNDRED AND FOURTY-FIVE RUPIAHS FIFTY-SIX
CREATE OR REPLACE PACKAGE PKG_DIGIT_SPELLER IS
/*******************************************************************************

  Nama Package : PKG_DIGIT_SPELLER
  Oleh         : Ibrahim F Burhan (ibrahim@burhan.biz)
  Deskripsi    : Menghasilkan ucapan bilangan dalam bahasa Indonesia dan
                 Inggris

  Hak Cipta Oleh Ibrahim F Burhan (ibrahim@burhan.biz) 2000

  Siapa saja diperkenankan untuk memakai, mengubah ataupun mengembangkan
  source code ini, dengan syarat tetap mencantumkan keterangan ini.

  Reposted from my archive (Mar 16, 2001)
*******************************************************************************/
  TYPE typeSpellString IS VARRAY(100) OF VARCHAR2(20);

  arrSpellString typeSpellString;

  /* Bahasa Indonesia */
  FUNCTION INA(vchrDigitString VARCHAR2) RETURN VARCHAR2;

  /* English */
  FUNCTION ENG(vchrDigitString VARCHAR2) RETURN VARCHAR2;

  /* Bahasa Indonesia */
  FUNCTION INARupiah(vchrDigitString VARCHAR2) RETURN VARCHAR2;

  /* English */
  FUNCTION ENGRupiah(vchrDigitString VARCHAR2) RETURN VARCHAR2;
END;

CREATE OR REPLACE PACKAGE BODY PKG_DIGIT_SPELLER IS

  /* Initialization */
  /* Must be called before executing other procedures */
  PROCEDURE Initialize IS
  BEGIN
    arrSpellString := typeSpellString ('SATU ',           --1
                                       'DUA ',
                                       'TIGA ',
                                       'EMPAT ',
                                       'LIMA ',
                                       'ENAM ',
                                       'TUJUH ',
                                       'DELAPAN ',
                                       'SEMBILAN ',
                                       'PULUH ',          --10
                                       'BELAS ',
                                       'SE',
                                       'RATUS ',
                                       NULL,
                                       'RIBU ',
                                       'JUTA ',
                                       'MILYAR ',
                                       'TRILIUN ',
                                       NULL,
                                       NULL,             --20
                                       'ONE ',
                                       'TWO ',
                                       'THREE ',
                                       'FOUR ',
                                       'FIVE ',
                                       'SIX ',
                                       'SEVEN ',
                                       'EIGHT ',
                                       'NINE ',
                                       'TEN ',            --30
                                       'ELEVEN ',
                                       'TWELVE ',
                                       'THIRTEEN ',
                                       'FOURTEEN ',
                                       'FIFTEEN ',
                                       'SIXTEEN ',
                                       'SEVENTEEN ',
                                       'EIGHTEEN ',
                                       'NINETEEN ',
                                       'TWENTY',        --40
                                       'THIRTY',
                                       'FOURTY',
                                       'FIFTY',
                                       'SIXTY',
                                       'SEVENTY',
                                       'EIGHTY',
                                       'NINETY',
                                       'AND ',
                                       'HUNDRED ',
                                       NULL,            --50
                                       'THOUSAND ',
                                       'MILLION ',
                                       'BILLION ',
                                       'TRILLION ');
  END;

  /* Bahasa Indonesia two digit spelling */
  FUNCTION INASpell2(vchrDigit2 VARCHAR2) RETURN VARCHAR2 IS
    intLen NUMBER;
    chrDigit1 CHAR(1);
        chrDigit2 CHAR(1);
  BEGIN
    intLen := LENGTH(vchrDigit2);
    chrDigit1 := SUBSTR(vchrDigit2, 1, 1);
    chrDigit2 := SUBSTR(vchrDigit2, 2, 1);

        IF intLen = 2 THEN
          IF (chrDigit1 = '0') THEN
            BEGIN
              IF (chrDigit2 = '0') THEN
                    RETURN arrSpellString(14);
                  ELSE
                RETURN arrSpellString(TO_NUMBER(chrDigit2));
                  END IF;
            END;
          ELSIF (chrDigit1 = '1') THEN
            BEGIN
              IF (chrDigit2 = '0') THEN
                    RETURN arrSpellString(12)||arrSpellString(10);
                  ELSIF (chrDigit2 = '1') THEN
                    RETURN arrSpellString(12)||arrSpellString(11);
                  ELSE
                    RETURN arrSpellString(TO_NUMBER(chrDigit2))||arrSpellString(11);
                  END IF;
            END;
          ELSE
            BEGIN
              IF (chrDigit2 = '0') THEN
                    RETURN arrSpellString(TO_NUMBER(chrDigit1))||arrSpellString(10);
                  ELSE
                    RETURN arrSpellString(TO_NUMBER(chrDigit1))||arrSpellString(10)||arrSpellString(TO_NUMBER(chrDigit2));
                  END IF;
            END;
          END IF;
        ELSE
          RETURN arrSpellString(TO_NUMBER(chrDigit1));
        END IF;
  END;

  /* Bahasa Indonesia three digit spelling */
  FUNCTION INASpell3(vchrDigit3 VARCHAR2) RETURN VARCHAR2 IS
    intLen NUMBER(1);
        chrDigit1 CHAR(1);
        chrDigit2 CHAR(1);
        chrDigit3 CHAR(1);
  BEGIN
    intLen := LENGTH(vchrDigit3);
    chrDigit1 := SUBSTR(vchrDigit3, 1, 1);
    chrDigit2 := SUBSTR(vchrDigit3, 2, 1);
    chrDigit3 := SUBSTR(vchrDigit3, 3, 1);

        IF (intLen = 1) THEN
          BEGIN
            IF (chrDigit1 = '0') THEN
                  RETURN arrSpellString(14);
                ELSE
              RETURN arrSpellString(TO_NUMBER(chrDigit1));
                END IF;
          END;
        ELSIF (intLen = 2) THEN
          BEGIN
            RETURN INASpell2(vchrDigit3);
          END;
        ELSE
          BEGIN
            IF (chrDigit1 = '0') THEN
              RETURN INASpell2(SUBSTR(vchrDigit3, -2, 2));
                ELSIF (chrDigit1 = '1') THEN
                  RETURN arrSpellString(12)||arrSpellString(13)||INASpell2(SUBSTR(vchrDigit3, -2, 2));
                ELSE
              RETURN arrSpellString(TO_NUMBER(chrDigit1))||arrSpellString(13)||INASpell2(SUBSTR(vchrDigit3, -2, 2));
                END IF;
          END;
        END IF;
  END;

  /* Bahasa Indonesia integer spelling */
  FUNCTION INASpellInteger(vchrDigitInteger VARCHAR2) RETURN VARCHAR2 IS
    intLen NUMBER;
        int3DigitCount NUMBER;
        intStart NUMBER;
        intLenSub NUMBER;
        i NUMBER;
        vchrSpell VARCHAR2(512) := '';
        vchrSpellTemp VARCHAR2(512) := NULL;
  BEGIN
    intLen := LENGTH(vchrDigitInteger);
        int3DigitCount := CEIL(intLen / 3);
        intStart := 1;

        FOR i IN 1..int3DigitCount LOOP
          intStart := i * 3;
          intLenSub := 3;
          IF (intStart > intLen) THEN
                intLenSub := intLen - (intStart - 3);
            intStart := intLen;
          END IF;

          vchrSpellTemp := INASpell3(SUBSTR(vchrDigitInteger, -intStart, intLenSub));

          IF vchrSpellTemp IS NULL THEN
            vchrSpell := vchrSpell;
          ELSE
            vchrSpell := vchrSpellTemp||arrSpellString(13+i)||vchrSpell;
          END IF;

        END LOOP;

        RETURN vchrSpell;
  END;

  /* Bahasa Indonesia spelling */
  FUNCTION INA(vchrDigitString VARCHAR2) RETURN VARCHAR2 IS
  BEGIN
    Initialize;

    RETURN INASpellInteger(vchrDigitString);
  END;

  /* English two digit spelling */
  FUNCTION ENGSpell2(vchrDigit2 VARCHAR2) RETURN VARCHAR2 IS
    intLen NUMBER;
    chrDigit1 CHAR(1);
        chrDigit2 CHAR(1);
  BEGIN
    intLen := LENGTH(vchrDigit2);
    chrDigit1 := SUBSTR(vchrDigit2, 1, 1);
    chrDigit2 := SUBSTR(vchrDigit2, 2, 1);

    IF intLen = 2 THEN
          IF (chrDigit1 = '0') THEN
            BEGIN
              IF (chrDigit2 = '0') THEN
                    RETURN arrSpellString(14);
                  ELSE
                RETURN arrSpellString(20+TO_NUMBER(chrDigit2));
                  END IF;
            END;
          ELSIF (chrDigit1 = '1') THEN
            BEGIN
          RETURN arrSpellString(30+TO_NUMBER(chrDigit2));
            END;
          ELSE
            BEGIN
              IF (chrDigit2 = '0') THEN
                    RETURN arrSpellString(38+TO_NUMBER(chrDigit1))||' ';
                  ELSE
                    RETURN arrSpellString(38+TO_NUMBER(chrDigit1))||'-'||arrSpellString(20+TO_NUMBER(chrDigit2));
                  END IF;
            END;
          END IF;
        ELSE
          RETURN arrSpellString(20+TO_NUMBER(chrDigit1));
        END IF;
  END;

  /* English three digit spelling */
  FUNCTION ENGSpell3(vchrDigit3 VARCHAR2) RETURN VARCHAR2 IS
    intLen NUMBER(1);
        chrDigit1 CHAR(1);
        chrDigit2 CHAR(1);
        chrDigit3 CHAR(1);
        vchrSpellTemp VARCHAR2(500);
  BEGIN
    intLen := LENGTH(vchrDigit3);
    chrDigit1 := SUBSTR(vchrDigit3, 1, 1);
    chrDigit2 := SUBSTR(vchrDigit3, 2, 1);
    chrDigit3 := SUBSTR(vchrDigit3, 3, 1);

        IF (intLen = 1) THEN
          BEGIN
            IF (chrDigit1 = '0') THEN
                  RETURN arrSpellString(14);
                ELSE
              RETURN arrSpellString(20+TO_NUMBER(chrDigit1));
                END IF;
          END;
        ELSIF (intLen = 2) THEN
          BEGIN
            RETURN ENGSpell2(vchrDigit3);
          END;
        ELSE
          BEGIN
            IF (chrDigit1 = '0') THEN
              RETURN ENGSpell2(SUBSTR(vchrDigit3, -2, 2));
                ELSE
                  vchrSpellTemp := ENGSpell2(SUBSTR(vchrDigit3, -2, 2));
                  IF vchrSpellTemp IS NULL THEN
                    RETURN arrSpellString(20+TO_NUMBER(chrDigit1))||arrSpellString(49)||vchrSpellTemp;
                  ELSE
                RETURN arrSpellString(20+TO_NUMBER(chrDigit1))||arrSpellString(49)||arrSpellString(48)||vchrSpellTemp;
                  END IF;
                END IF;
          END;
        END IF;
  END;

  /* English integer spelling */
  FUNCTION ENGSpellInteger(vchrDigitInteger VARCHAR2) RETURN VARCHAR2 IS
    intLen NUMBER;
        int3DigitCount NUMBER;
        intStart NUMBER;
        intLenSub NUMBER;
        i NUMBER;
        vchrSpell VARCHAR2(512) := '';
        vchrSpellTemp VARCHAR2(512) := NULL;
  BEGIN
    intLen := LENGTH(vchrDigitInteger);
        int3DigitCount := CEIL(intLen / 3);
        intStart := 1;

        FOR i IN 1..int3DigitCount LOOP
          intStart := i * 3;
          intLenSub := 3;
          IF (intStart > intLen) THEN
                intLenSub := intLen - (intStart - 3);
            intStart := intLen;
          END IF;

          vchrSpellTemp := ENGSpell3(SUBSTR(vchrDigitInteger, -intStart, intLenSub));

          IF vchrSpellTemp IS NULL THEN
            vchrSpell := vchrSpell;
          ELSE
            vchrSpell := vchrSpellTemp||arrSpellString(49+i)||vchrSpell;
          END IF;

        END LOOP;

        RETURN vchrSpell;
  END;

  /* English spelling */
  FUNCTION ENG(vchrDigitString VARCHAR2) RETURN VARCHAR2 IS
  BEGIN
    Initialize;

    RETURN ENGSpellInteger(vchrDigitString);
  END;

  /* Bahasa Indonesia spelling with Rupiah currency */
  FUNCTION INARupiah(vchrDigitString VARCHAR2) RETURN VARCHAR2 IS
    vchrInString VARCHAR2(30);
  BEGIN
    vchrInString := TO_CHAR(TRUNC(TO_NUMBER(vchrDigitString), 2));

    RETURN INA(TO_CHAR(TRUNC(TO_NUMBER(vchrInString))))||' RUPIAH '||
           INA(TO_CHAR((TO_NUMBER(vchrInString) - TRUNC(TO_NUMBER(vchrInString))) * 100));
  END;

  /* English spelling with Rupiah currency */
  FUNCTION ENGRupiah(vchrDigitString VARCHAR2) RETURN VARCHAR2 IS
    vchrInString VARCHAR2(30);
  BEGIN
    vchrInString := TO_CHAR(TRUNC(TO_NUMBER(vchrDigitString), 2));

    RETURN ENG(TO_CHAR(TRUNC(TO_NUMBER(vchrInString))))||' RUPIAHS '||
           ENG(TO_CHAR((TO_NUMBER(vchrInString) - TRUNC(TO_NUMBER(vchrInString))) * 100));
  END;

END ;

1 Feb 2007

Paradigma OO

Kata paradigma yang dimaksud dalam topik ini memiliki arti metodologi pengembangan perangkat lunak. Paradigma OO berarti metodologi pengembangan perangkat lunak dengan OO.


Sebelum lebih jauh membahas OO, akan dikupas sedikit tentang paradigma. Kenapa perlu paradigma atau metodologi untuk membuat perangkat lunak? Apa sih sebenarnya paradigm?

Saya akan mencoba menjelaskan bukan dengan definisi-definisi tetapi dengan sebuah ilustrasi. Perangkat lunak adalah suatu benda tak berwujud (intangible) yang berpasangan dengan perangkat keras yang dibuat untuk memenuhi suatu maksud atau tujuan tertentu. Tujuan atau maksud ini bisa jadi bagian dari sebuah sistem atau bahkan sistem itu sendiri. Manusia berperan dalam membangun atau membuat kedua perangkat tersebut, dan berperan untuk menggunakan atau menerima hasilnya. Misalnya perangkat lunak personalia, perangkat lunak tersebut dijalankan pada suatu komputer (perangkat keras) untuk menangani masalah-masalah yang terkait dengan pengelolaan sumber daya manusia sebuah perusahaan. Ada orang-orang yang terlibat dalam mengembangkan perangkat lunak dan ada orang-orang yang menjalankan atau memakainya.


Dari penjelasan di atas dapat dilihat ada beberapa hal atau elemen yang terlibat, yaitu perangkat lunak, perangkat keras, pembuat perangkat lunak, pemakai perangkat lunak dan masalah. Gambar 1 mengilustrasikan hubungan antara elemen tersebut.




Perangkat lunak merupakan perwujudan dari masalah dunia nyata. Perangkat lunak merupakan masalah dalam bentuk yang lain, dalam bentuk yang tak terlihat berupa kumpulan perintah yang dijalankan oleh perangkat keras. Pengubahan bentuk atau wujud ini dilakukan oleh manusia, yang kita kenal dengan istilah pengembangan perangkat lunak (software development) dan orangnya disebut juga pengembang (developer). Perangkat keras (komputer) adalah seonggok mesin yang pasif yang tak berguna tanpa adanya perangkat lunak. Demikian pula perangkat lunak tidak akan memenuhi tujuannya tanpa keberadaan perangkat keras. Sedangkan pemakai adalah manusia yang menerima manfaat dari perangkat lunak. Sebuah perangkat lunak seharusnya memberikan manfaat atau nilai tambah kepada pemakai, bukan sebaliknya.
Ada ungkapan seseorang mengenai perbedaan antara manusia dan komputer: Manusia adalah pintar, lambat dan khilaf, sedangkan komputer adalah bodoh, cepat dan akurat. Jadi komputer digunakan sebagai alat bantu untuk menutupi kekurangan manusia dan bukan menjadi tujuan.
Pengubahan masalah menjadi perangkat lunak saya istilahkan mapping (pemetaan). Pemetaan membuat representasi masalah dalam dunia nyata menjadi bentuk yang dapat ‘dipahami’ oleh mesin (komputer). Pemetaan ini merupakan proses-proses yang ada dalam pengembangan perangkat lunak. Setiap manusia memiliki pemikiran dan pemahaman yang berbeda, sehingga mempunyai ide yang berbeda pula dalam hal memandang sesuatu. Demikian pula ketika melihat masalah dan bagaimana cara pemetaan, setiap pengembang memiliki cara pandang yang berbeda. Hal inilah memunculkan keilmuan dalam bidang pengembangan perangkat lunak atau yang kita kenal dengan ilmu rekayasa perangkat lunak (software engineering).


Mainstream dari cara pandang tersebut saat ini ada beberapa, dua yang telah banyak dikenal adalah functional decomposition (penguraian fungsional) dan OO (object oriented). Kalau saya gambarkan, cara pandang penguraian fungsional melihat masalah dunia nyata sebagai serentetan fungsi-fungsi yang saling terkait. Jika sebuah fungsi masih dianggap besar atau kompleks maka fungsi tersebut dapat diuraikan (decompose) untuk menjadi beberapa fungsi yang lebih rinci atau kecil. Sebagai contoh dalam sebuah pengelolaan sumber daya manusia terdapat masalah mencetak slip gaji karyawan. Masalah tersebut dapat dipecahkan dengan langkah-langkah berikut:
  1. mencari data karyawan
  2. mencari data kehadiran
  3. menghitung gaji
  4. mencetak ke printer
Pada langkah ke-3, kita dapat menguraikan lebih rinci menjadi:
    3.a. mencari nilai gaji pokok
    3.b. menghitung upah lembur
    3.d. menjumlahkan nilai gaji pokok dan upah lembur
Cara pandang masalah seperti di ataslah yang dimaksud dengan penguraian fungsional.
Pada OO, masalah dipandang sebagai kumpulan objek-objek yang saling berinteraksi dan masing-masing memiliki tanggung jawab. Objek, ada yang mengatakan adalah sebuah entitas yang memiliki atribut atau kelakukan, atau sesuatu yang memiliki data dan method. Saya, mengilustrasikan objek sebagai sesuatu yang nyata (tangible) ataupun tidak (intangible) yang memiliki tanggung jawab (responsibility). Sebagai contoh, dalam sebuah pengelolaan sumber daya manusia dapat ditemukan obje-objek, antara lain:
  1. karyawan
  2. daftar hadir
  3. slip gaji
Objek karyawan memiliki tanggung jawab untuk bekerja sesuai aturan. Objek daftar hadir bertanggung jawab mencatat kehadiran dan ketidakhadiran karyawan. Objek slip gaji bertanggung jawab menampilkan gaji karyawan.
Letak perbedaan antara keduanya adalah dalam hal menangani perubahan kebutuhan (requirement change).
Paradigma OO vs Paradigma lainnya: Apakah OO lebih unggul?
Tidak ada obat mujarab buatan manusia yang menyembuhkan segala penyakit. Demikian pula tidak ada suatu paradigma pengembangan perangkat lunak yang dapat menyelesaian semua masalah. Paradigma OO bisa saja dipakai untuk semua masalah tapi, tetapi pengembangan perangkat lunak tidak hanya terletak pada hasil tetapi juga pada prosesnya. Ada beberapa aspek yang dipertimbangkan ketika memilih paradigma pada sebuah pengembangan perangkat lunak. Pertimbangan tersebut tentu harus terukur, bukankah pengembangan perangkat lunak termasuk dalam kategori ‘engineering’? Penerapan membabi buta sebuah paradigma tanpa pertimbangan melepas makna ‘engineering’ tersebut. Sama halnya ketika kita ingin memotong benang dengan kapak, atau menumbangkan pohon dengan pisau dapur (ungkapan ini saya dapat dari dosen saya ketika kuliah).