Living life and Make it Better

life, learn, contribute

Endy Muhardin

Software Developer berdomisili di Jabodetabek, berkutat di lingkungan open source, terutama Java dan Linux.

Mendebug Database Production

Suatu aplikasi, walaupun sudah go-live di environment production, tetap bisa saja mengalami error dan bug. Bug ini seringkali tidak ditemukan di environment development karena berbagai hal, misalnya variasi data, jumlah data, dan sebagainya.

Langkah pertama ketika kita mengetahui ada bug tentunya adalah melokalisir masalah. Pada kondisi mana saja bug tersebut muncul. Setelah itu, kita dapat memfokuskan pencarian masalah di lokasi tersebut. Ini lebih efisien daripada kita harus menelusuri keseluruhan sistem.

Misalnya kita sudah berhasil melokalisir masalah, yaitu transaksi di bulan tertentu. Langkah selanjutnya adalah memindahkan data production di lokasi tersebut ke environment development. Ini kita lakukan supaya kita bebas bereksperimen dengan data tersebut tanpa khawatir membahayakan data production.

Masalahnya, tools backup database yang tersedia biasanya tidak bisa digunakan untuk mengambil sebagian data. Walaupun bisa (mysqldump menyediakan opsi where untuk membatasi record yang diambil), biasanya terbatas hanya di satu tabel saja. Sedangkan untuk bisa merestore-nya di development, kita butuh semua relasinya.

Sebagai contoh, coba lihat skema berikut.

Untuk mengambil data payment, tentunya kita juga harus menarik data lain yang berelasi dengannya, yaitu di tabel grup loket, loket, payment value, payment info dan fee loket. Ini sangat sulit dilakukan, apalagi kalau data payment tersebut jumlahnya ratusan ribu record.

Untunglah ada tools untuk mengatasi masalah ini, namanya Jailer. Dengan menggunakan Jailer, kita dapat menentukan tabel mana yang akan diambil datanya (payment), kriteria pengambilan (bulan tertentu saja), dan relasi mana saja yang ingin kita ambil. Hasilnya adalah satu set data lengkap dengan dependensinya yang bisa kita restore di development.

Persiapan Jailer

Pertama, tentunya kita unduh dulu Jailer di websitenya. Jangan lupa teriakkan, “Hidup Open Source !!!”, karena aplikasi ini tersedia secara gratis berkat gerakan open source.

Setelah berhasil diunduh, extract ke folder tertentu. Jailer tidak menyertakan driver untuk koneksi ke database, sehingga kita harus sediakan sendiri. Karena saya menggunakan MySQL, saya masukkan file mysql-connector.jar ke dalam folder lib. Kita mengikutkan driver database ke folder Jailer karena nantinya folder ini akan kita pack dan upload ke server production.

Jailer ini akan kita jalankan di mesin development yang sudah terisi skema database. Kita akan coba dulu ambil data di development, kalau sudah sukses baru kita jalankan di production.

Ada dua script untuk menjalankan jailer, yaitu jailerGUI dan jailer. jailerGUI digunakan untuk mendesain pengambilan data, sedangkan jailer adalah antarmuka command line untuk menjalankan pengambilan data. Karena kita ingin mendesain proses pengambilannya, kita gunakan jailerGUI.

$ sh jailerGUI.sh

Berikut adalah tampilan awal Jailer.

Jailer Welcome Page

Jailer memberitahu kita bahwa belum ada data model yang bisa dikerjakan, dan menyarankan kita untuk menganalisa database. Klik Analyze Database. Selanjutnya Jailer akan meminta informasi cara koneksi ke database.

Analyze Database

Isikan informasi koneksi database dan driver yang digunakan. Driver yang kita gunakan adalah yang tadi sudah kita copy ke folder lib.

Konfigurasi MySQL

Klik OK untuk menganalisa database.

Koneksi ke database

Setelah itu, Jailer akan menghubungi database untuk mengambil informasi. Lognya akan ditampilkan di log output. Jailer akan memberi tahu kita tabel-tabel yang tidak ada primary keynya. Jailer tidak dapat memproses tabel tanpa primary key.

Hasil Autodetect

Klik tabel yang berwarna merah, dan definisikan primary keynya. Primary key yang kita definisikan di sini hanya digunakan Jailer, sehingga tidak perlu khawatir skema aslinya akan berubah.

Add Primary Key

Setelah itu, klik OK. Jailer akan menampilkan screen Extraction Model Editor. Pilih tabel payment, di dropdown subject, karena inilah tabel yang akan kita gunakan sebagai pusat extraction.

Pilih tabel yang ingin diimport

Jailer mendeteksi relasi antar tabel berdasarkan constraint foreign key yang kita pasang di database. Kadangkala ada tabel-tabel yang berelasi, namun tidak ada constraintnya. Entah karena malas mendefinisikan, atau memang sengaja tidak dikaitkan. Kita bisa mendaftarkan relasi tanpa constraint ini dengan membuka lagi Data Model Editor, kemudian klik Add di kotak Association sebelah kanan.

Relasi non Foreign Key

Setelah diklik OK, maka skema relasi di Extraction Model Editor akan berubah sesuai relasi yang ditambahkan. Sama dengan definisi primary key di atas, relasi ini hanya disimpan oleh Jailer dan tidak diaplikasikan ke skema database.

Relasi Payment - Loket

Kita perlu mendefinisikan batasan record payment yang akan diambil, yaitu yang terjadi di bulan Juni 2010. Dalam bentuk SQL, berikut adalah query yang digunakan

select * from payment where date_format(paid_date, '%Y-%m') = '2010-06'

Kita ambil expression setelah where dan pasang di textfield where dalam Extraction Model Editor.

Restriction

Simpan dulu extraction modelnya.

Save Extraction

Beri nama yang representatif, misalnya payment-201006. Jailer akan menyimpan extraction model ini dalam format csv. Kalau sudah memahami formatnya, kita bisa membuatnya dengan text editor tanpa GUI (kalau mau).

Setelah tersimpan, kita bisa klik Export Data sehingga memunculkan dialog berikut.

Export Data

Di screen tersebut kita bisa mengatur konfigurasi pengambilan data. Bagi saya, nilai defaultnya sudah memadai sehingga tidak ada yang diubah.

Di box paling bawah ada command line yang bisa kita copy-paste untuk dijalankan tanpa GUI. Copy saja isinya ke text file untuk digunakan nanti.

Yang harus kita isi di screen ini adalah textfield Into. Ini adalah nama file yang akan menampung script SQL berisi data yang diinginkan. Isi saja dengan nama payment-201006.sql.

Export Into File

Setelah itu, klik Export Data. Jailer akan segera bekerja dan menampilkan hasilnya dalam bentuk tree.

Hasil Export

Di situ kita bisa lihat berapa row yang akan diambil dari masing-masing tabel. Seperti kita lihat, cukup signifikan, yaitu 2000an record. Ini disebabkan karena jailer mengambil record secara rekursif tanpa ada batasan.

Setelah dianalisa, kita hanya ingin mengambil tabel-tabel yang berkaitan langsung, yaitu payment, payment_info, payment_value, dan fee_loket. Sedangkan tabel sisanya dapat diabaikan karena bersifat pelengkap atau master data yang sudah ada di database development.

Dengan melihat ke tree-nya, kita bisa memutus relasi fee_loket ke loket, karena dari situlah semua data lain akan ikut terbawa.

Tutup screennya, dan kembali ke Extraction Model Editor.

Membatasi Relasi

Di kotak Association, expand node yang ingin kita putuskan, yaitu fee loket. Klik relasi loket, dan centang checkbox disabled di pojok kiri bawah. Setelah itu, jalankan lagi Export Data.

Warning Restricted Dependency

Jailer akan mengingatkan bahwa dengan membatasi dependensi, referential integrity akan rusak, karena relasi foreign key dari fee_loket ke loket akan terputus. Klik saja Yes, karena di database development kita tabel loket sudah terisi lengkap.

Inilah hasilnya

Hasil Export setelah dibatasi

Seperti kita lihat di atas, kita cuma mendapatkan 84 record dan pengambilan data berhenti di tabel fee_loket. Periksa output payment-201006.sql di folder Jailer untuk memastikan hasilnya sudah benar.

Setelah sukses dijalankan di database development, compress lagi jailer yang sudah dimodifikasi barusan dan upload ke server production. Setibanya di server production, extract, kemudian jalankan script yang tadi kita copy-paste.

Kalau baru pertama kali dijalankan, script ini akan menimbulkan error sebagai berikut :

$ ./export-payment-201006.sh 
2010-06-28 14:15:08,114 [main] INFO   - Jailer 3.4.5
2010-06-28 14:15:08,117 [main] INFO   - added 'lib/mysql-connector-java-5.1.6-bin.jar' to classpath
2010-06-28 14:15:08,119 [main] INFO   - exporting 'extractionmodel/payment-201006.csv' to 'payment-201006.sql'
2010-06-28 14:15:08,700 [main] INFO   - begin guessing SQL dialect
2010-06-28 14:15:08,711 [main] INFO   - end guessing SQL dialect
2010-06-28 14:15:08,718 [main] ERROR  - Can't find working tables! Run 'bin/jailer.sh create-ddl' and execute the DDL-script first!
java.lang.RuntimeException: Can't find working tables! Run 'bin/jailer.sh create-ddl' and execute the DDL-script first!
	at net.sf.jailer.entitygraph.EntityGraph.create(EntityGraph.java:122)
	at net.sf.jailer.Jailer.export(Jailer.java:1142)
	at net.sf.jailer.Jailer.jailerMain(Jailer.java:1064)
	at net.sf.jailer.Jailer.jailerMain(Jailer.java:989)
	at net.sf.jailer.Jailer.main(Jailer.java:967)
Caused by: java.sql.SQLException: "Table 'ppobgsp_test.JAILER_GRAPH' doesn't exist" in statement "Insert into JAILER_GRAPH(id, age) values (2104021762, 1)"
	at net.sf.jailer.database.Session.executeUpdate(Session.java:470)
	at net.sf.jailer.entitygraph.EntityGraph.create(EntityGraph.java:120)
	... 4 more
Error: java.lang.RuntimeException: Can't find working tables! Run 'bin/jailer.sh create-ddl' and execute the DDL-script first!
2010-06-28 14:15:08,724 [main] ERROR  - working directory is /opt/downloads/java/tools/test/integration-test/jailer

Ini disebabkan karena Jailer ternyata membuat beberapa tabel di database untuk kebutuhan internalnya. Ini dapat dilihat pada database development kita.

Tabel Internal Jailer

Untuk menggenerate tabel di atas, kita jalankan jailer dengan opsi create-ddl. Ini akan menghasilkan SQL di layar. SQL ini harus kita jalankan di database production supaya tabelnya terbentuk.

$ sh jailer.sh create-ddl
DROP TABLE JAILER_ENTITY;
DROP TABLE JAILER_DEPENDENCY;
DROP TABLE JAILER_SET;
DROP TABLE JAILER_GRAPH;
DROP TABLE JAILER_CONFIG;
DROP TABLE JAILER_TMP;

CREATE TABLE JAILER_CONFIG
(
   jversion        VARCHAR(20),
   jkey            VARCHAR(200),
   jvalue          VARCHAR(200)
) ;

INSERT INTO JAILER_CONFIG(jversion, jkey, jvalue) values('3.4.5', 'magic', '837065098274756382534403654245288');

CREATE TABLE JAILER_GRAPH
(
   id              INTEGER NOT NULL,
   age             INTEGER NOT NULL
      
--   ,CONSTRAINT jlr_pk_graph PRIMARY KEY(id)
) ;

CREATE TABLE JAILER_ENTITY
(
   r_entitygraph   INTEGER NOT NULL,

   PK0 BIGINT , PK1 VARCHAR(255) , PK2 VARCHAR(255) , PK3 INT , PK4 VARCHAR(255) , PK5 BIGINT ,
   birthday        INTEGER NOT NULL,
   type            VARCHAR(120) NOT NULL,

   PRE_PK0 BIGINT , PRE_PK1 VARCHAR(255) , PRE_PK2 VARCHAR(255) , PRE_PK3 INT , PRE_PK4 VARCHAR(255) , PRE_PK5 BIGINT ,
   PRE_TYPE        VARCHAR(120),
   orig_birthday   INTEGER,
   association     INTEGER

-- ,  CONSTRAINT jlr_fk_graph_e FOREIGN KEY (r_entitygraph) REFERENCES JAILER_GRAPH(id)
) ;

CREATE INDEX jlr_enty_brthdy ON JAILER_ENTITY (r_entitygraph, birthday, type) ;
CREATE INDEX jlr_enty_upk1 ON JAILER_ENTITY (r_entitygraph , PK0, PK1, PK2, PK3, PK4, PK5, type) ;


CREATE TABLE JAILER_SET
(
   set_id          INTEGER NOT NULL,
   type            VARCHAR(120) NOT NULL,
   PK0 BIGINT , PK1 VARCHAR(255) , PK2 VARCHAR(255) , PK3 INT , PK4 VARCHAR(255) , PK5 BIGINT 
) ;

CREATE INDEX jlr_pk_set1 ON JAILER_SET (set_id , PK0, PK1, PK2, PK3, PK4, PK5, type) ;


CREATE TABLE JAILER_DEPENDENCY
(
   r_entitygraph   INTEGER NOT NULL,
   assoc           INTEGER NOT NULL,
   depend_id       INTEGER NOT NULL,
   traversed       INTEGER,
   from_type       VARCHAR(120) NOT NULL,
   to_type         VARCHAR(120) NOT NULL,
   FROM_PK0 BIGINT , FROM_PK1 VARCHAR(255) , FROM_PK2 VARCHAR(255) , FROM_PK3 INT , FROM_PK4 VARCHAR(255) , FROM_PK5 BIGINT ,
   TO_PK0 BIGINT , TO_PK1 VARCHAR(255) , TO_PK2 VARCHAR(255) , TO_PK3 INT , TO_PK4 VARCHAR(255) , TO_PK5 BIGINT    

-- ,  CONSTRAINT jlr_fk_graph_d FOREIGN KEY (r_entitygraph) REFERENCES JAILER_GRAPH(id)
) ;

CREATE INDEX jlr_dep_from1 ON JAILER_DEPENDENCY (r_entitygraph, assoc , FROM_PK0, FROM_PK1, FROM_PK2, FROM_PK3, FROM_PK4, FROM_PK5) ;

CREATE INDEX jlr_dep_to1 ON JAILER_DEPENDENCY (r_entitygraph , TO_PK0, TO_PK1, TO_PK2, TO_PK3, TO_PK4, TO_PK5) ;


CREATE TABLE JAILER_TMP 
(
    c1 INTEGER, 
    c2 INTEGER
) ;

INSERT INTO JAILER_CONFIG(jversion, jkey, jvalue) values('3.4.5', 'upk', '679547784');

Setelah tabelnya siap, jalankan kembali script yang error di atas. Berikut outputnya.

$ ./export-payment-201006.sh 
2010-06-28 14:12:31,175 [main] INFO   - Jailer 3.4.5
2010-06-28 14:12:31,190 [main] INFO   - added 'lib/mysql-connector-java-5.1.6-bin.jar' to classpath
2010-06-28 14:12:31,191 [main] INFO   - exporting 'extractionmodel/payment-201006.csv' to 'payment-201006.sql'
2010-06-28 14:12:32,850 [main] INFO   - SQL dialect is MYSQL
2010-06-28 14:12:32,925 [main] INFO   - gather statistics after 0 inserted rows...
2010-06-28 14:12:32,966 [main] INFO   - reading file 'renew.sql'
2010-06-28 14:12:32,966 [main] INFO   - 0 statements (100%)
2010-06-28 14:12:32,967 [main] INFO   - successfully read file 'renew.sql'
2010-06-28 14:12:32,977 [main] INFO   - exporting payment Where date_format(paid_date,'%Y-%m') = '2010-06'
2010-06-28 14:12:33,028 [main] INFO   - day 1, progress: payment
2010-06-28 14:12:33,039 [main] INFO   - starting 4 jobs
2010-06-28 14:12:33,040 [main] INFO   - gather statistics after 3 inserted rows...
2010-06-28 14:12:33,041 [main] INFO   - reading file 'renew.sql'
2010-06-28 14:12:33,042 [main] INFO   - 0 statements (100%)
2010-06-28 14:12:33,042 [main] INFO   - successfully read file 'renew.sql'
2010-06-28 14:12:33,047 [main] INFO   - resolving payment -> payment_info (inverse-FKE25C3F47AB64A229) 1:n on B.id_payment=A.id...
2010-06-28 14:12:33,105 [main] INFO   - 66 entities found resolving payment -> payment_info (inverse-FKE25C3F47AB64A229) 1:n on B.id_payment=A.id
2010-06-28 14:12:33,105 [main] INFO   - resolving payment -> cetak_ulang (inverse-FK45B985E0AB64A229) 1:n on B.id_payment=A.id...
2010-06-28 14:12:33,126 [main] INFO   - 0 entities found resolving payment -> cetak_ulang (inverse-FK45B985E0AB64A229) 1:n on B.id_payment=A.id
2010-06-28 14:12:33,126 [main] INFO   - resolving payment -> fee_loket (inverse-FK9632AFFEAB64A229) 1:n on B.id_payment=A.id...
2010-06-28 14:12:33,129 [main] INFO   - 3 entities found resolving payment -> fee_loket (inverse-FK9632AFFEAB64A229) 1:n on B.id_payment=A.id
2010-06-28 14:12:33,131 [main] INFO   - resolving payment -> payment_value (inverse-FK69DD09F8AB64A229) 1:n on B.id_payment=A.id...
2010-06-28 14:12:33,142 [main] INFO   - 12 entities found resolving payment -> payment_value (inverse-FK69DD09F8AB64A229) 1:n on B.id_payment=A.id
2010-06-28 14:12:33,143 [main] INFO   - executed 4 jobs
2010-06-28 14:12:33,143 [main] INFO   - day 2, progress: payment_info, fee_loket, payment_value
2010-06-28 14:12:33,144 [main] INFO   - skip reversal association payment_info -> payment
2010-06-28 14:12:33,144 [main] INFO   - skip reversal association fee_loket -> payment
2010-06-28 14:12:33,147 [main] INFO   - skip reversal association payment_value -> payment
2010-06-28 14:12:33,147 [main] INFO   - starting 1 jobs
2010-06-28 14:12:33,148 [main] INFO   - executed 1 jobs
2010-06-28 14:12:33,149 [main] INFO   - exported payment Where date_format(paid_date,'%Y-%m') = '2010-06'
2010-06-28 14:12:33,149 [main] INFO   - total progress: payment_info, payment, fee_loket, payment_value
2010-06-28 14:12:33,149 [main] INFO   - export statistic:
2010-06-28 14:12:33,169 [main] INFO   - Exported Rows:     84
2010-06-28 14:12:33,169 [main] INFO   -     fee_loket                      3
2010-06-28 14:12:33,169 [main] INFO   -     payment                        3
2010-06-28 14:12:33,172 [main] INFO   -     payment_info                   66
2010-06-28 14:12:33,172 [main] INFO   -     payment_value                  12
2010-06-28 14:12:33,173 [main] INFO   - writing file 'payment-201006.sql'...
2010-06-28 14:12:33,178 [main] INFO   - independent tables: payment
2010-06-28 14:12:33,179 [main] INFO   - starting 1 jobs
2010-06-28 14:12:33,380 [main] INFO   - executed 1 jobs
2010-06-28 14:12:33,380 [main] INFO   - independent tables: payment_info, fee_loket, payment_value
2010-06-28 14:12:33,384 [main] INFO   - starting 3 jobs
2010-06-28 14:12:33,447 [main] INFO   - executed 3 jobs
2010-06-28 14:12:33,447 [main] INFO   - cyclic dependencies for: 
2010-06-28 14:12:33,447 [main] INFO   - starting 0 jobs
2010-06-28 14:12:33,448 [main] INFO   - executed 0 jobs
2010-06-28 14:12:33,448 [main] INFO   - gather statistics after 84 inserted rows...
2010-06-28 14:12:33,450 [main] INFO   - reading file 'renew.sql'
2010-06-28 14:12:33,450 [main] INFO   - 0 statements (100%)
2010-06-28 14:12:33,454 [main] INFO   - successfully read file 'renew.sql'
2010-06-28 14:12:33,456 [main] INFO   - starting 0 jobs
2010-06-28 14:12:33,467 [main] INFO   - executed 0 jobs
2010-06-28 14:12:33,486 [main] INFO   - file 'payment-201006.sql' written.

Selesai sudah, data yang kita inginkan ada di file payment-201006.sql, siap diunduh dan dijalankan di database development.

Semoga bermanfaat, kalau ada yang kurang jelas, silahkan baca tutorial resminya.


Tuning Performance

Setelah aplikasi dicoding dengan benar, biasanya langkah berikutnya adalah tuning performance. Hal ini banyak ditanyakan di berbagai milis pemrograman yang saya ikuti. Agar tidak berkali-kali menulis jawaban yang sama, berikut artikel tentang metodologi saya dalam melakukan tuning performance aplikasi.

0. Miliki tujuan yang jelas

Misalnya : Mampu menghandle 100 request/detik dengan response time < 2 detik dengan 1 juta record di database. Bisa jadi pada tahap ini, ternyata keputusannya adalah tidak perlu tuning, karena performance aplikasi yang sekarang sudah memenuhi keinginan.

1. Pastikan aplikasinya berjalan benar

Make it right, then make it fast. Gak ada gunanya mentuning aplikasi buggy. Kita juga harus punya perangkat pengetes yang lengkap. Supaya nanti setelah tuning, bisa dipastikan bahwa tuningnya tidak menimbulkan bug baru.

2. Pasang monitor di aplikasi

Misalnya :

  • CPU usage
  • Memory usage
  • Aktifitas harddisk
  • Aktifitas database

Di linux, CPU dan Memory usage bisa dipantau dengan top, sedangkan aktifitas harddisk dengan iostat. Di MySQL, aktifitas database bisa dimonitor dengan perintah show processlist.

3. Setelah monitor siap, penyiksaan dimulai

Berikan load yang tinggi ke aplikasi dengan menggunakan tools penyiksaan seperti misalnya JMeter. Tingkatkan terus loadnya sampai response time tidak lagi memenuhi syarat. Misalnya, pada 30 request/detik, response time menjadi 10 detik.

4. Cari bottlenecknya

Amati monitor, aspek mana yang overload. Apakah CPU, I/O, atau memori. Perhatikan juga aktifitas database untuk mencari penyebabnya.

5. Lakukan tuning

Silahkan dioprek dengan metode trial and error. Biasanya pada tahap ini saya mencari kolom mana yang perlu diindex, bagian mana di source code yang perlu diperbaiki, atau konfigurasi seperti apa yang optimal.

6. Test lagi

Setelah dioprek, jalankan lagi tools penyiksaan. Kalau langkah no #5 benar, biasanya bottlenecknya akan pindah. Misalnya, tadinya CPU maxed out 100%, setelah tuning jadi santai 10%, tapi memory usage jadi 80%.

7. Ulangi langkah #5 dan #6

Ulangi terus tuning dan test sampai aplikasi memenuhi tujuan yang diset di langkah #0. Inilah pentingnya langkah #0, supaya kita tahu kapan harus berhenti.

Beberapa hal yang harus diingat dalam tuning performance:

  1. Tidak ada pil ajaib, masing-masing kasus berbeda. Kadang masalahnya ada di index database, kadang di prosesor, dsb.

  2. Jangan main tebak-tebakan, semua keputusan harus berdasarkan hasil monitoring. Soalnya seringkali tebakan kita salah.

  3. Jangan lupakan maintenance source code. Proses tuning mungkin saja akan membuat source code menjadi kompleks dan sulit dibaca. Jangan sampai kita mengorbankan kerapian coding demi sedikit peningkatan performance. Lebih baik upgrade hardware daripada mengotori source code.

  4. Tahu kapan harus berhenti. Tuning merupakan pekerjaan yang menarik, mirip seperti bermain game. Oleh karena itu penting bagi kita untuk punya tujuan. Begitu tujuan dicapai, segera berhenti. Lebih baik menambah fitur yang memiliki business value daripada terus menerus berkutat dengan performance.

Demikian sekilas tentang tuning. Semoga bermanfaat.


Fase Requirement

Dari seluruh fase yang ada di project, fase Requirement Development adalah yang paling penting. Bila kita melakukan kegiatan requirement dengan asal-asalan, akibatnya antara lain :

  • aplikasi sudah selesai dibuat, tapi tidak sesuai dengan keinginan user

  • pada fase coding, banyak terjadi delay karena ternyata ada requirement yang belum jelas

  • pada fase coding, banyak pekerjaan harus diulang karena salah memahami requirement

Kenapa saya sebut dengan istilah Requirement Development, bukan Requirement Gathering seperti yang umum dipakai orang? Sebabnya adalah karena requirement yang baik itu tidak didapat dengan mudah. Tidak seperti memungut barang di jalanan (gathering), melainkan harus melalui proses yang iteratif (development). Kita tidak bisa mendapatkan requirement yang baik sekali jalan. Kita harus terus menerus melakukan investigasi, klarifikasi, verifikasi, agar requirement yang didapat benar-benar bagus kualitasnya.

Pada artikel ini, kita akan membahas bagaimana cara membuat requirement yang baik.

Sebelum ke masalah teknis, kita lihat dulu, kenapa kita harus melalui fase requirement? Kenapa tidak langsung coding saja? Kan customer ingin aplikasi jadi, bukan notulensi meeting dan setumpuk dokumen?

Tujuan Requirement

Kita melakukan requirement development karena kita ingin tahu apa yang ingin dibuat. Setelah mengetahui apa yang ingin dibuat, barulah kita bisa:

  • memilih anggota tim yang tepat

  • memperkirakan biaya dan waktu yang dibutuhkan untuk membuatnya

  • memilih arsitektur dan teknologi yang sesuai

Jadi, proses requirement membantu kita untuk melakukan project planning. Selain itu, proses requirement juga membantu kita mencegah project menjadi molor dan merugi. Kalau kita langsung terjun coding, maka akan banyak waktu terbuang untuk melakukan perubahan. Misalnya, kalau kita sudah coding, ternyata user minta tambahan satu field entry, maka kita terpaksa mengubah tampilan, skema database, format report, dokumentasi user (kalau sudah ada), dan mungkin banyak lagi. Tapi kalau perubahan ini dilakukan pada fase requirement, paling effortnya cuma mengubah dummy dan dokumentasi user story saja.

Requirement juga bisa membantu kita mengendalikan perubahan dalam project, seperti kita akan lihat di bagian selanjutnya.

Setelah kita tahu tujuannya, mari kita ke langkah pertama yang paling menentukan.

Identifikasi Usernya

Segera setelah project dimulai, kita akan segera dihujani jadwal meeting untuk membahas requirement. Nah di sini kita harus jeli. Mendengarkan user itu penting, tapi yang lebih penting lagi adalah menjawab pertanyaan, siapa usernya?

Ada bermacam-macam jenis user, dan ini menentukan informasi apa yang ingin kita dengarkan, dan informasi mana yang kita abaikan.

  • End User. Ini adalah user yang nantinya akan menggunakan aplikasi. Kita harus mendengarkan user ini, terutama dari sisi usability. Apakah aplikasi kita nyaman dipakai, mudah digunakan, indah dilihat, dan sebagainya. Tapi, jangan sekali-kali mengambil keputusan tentang proses bisnis dengan user ini. Jangan juga memutuskan untuk menambah/mengurangi fitur hanya berdasarkan pendapat user ini. Kita membutuhkan user selanjutnya, yaitu :

  • Sponsor atau Client. Ini adalah orang yang akan membayar invoice untuk pembuatan aplikasi. Semua keputusan penting (proses bisnis dan list fitur adalah penting) harus disetujui Client. Dan jangan salah, seringkali pendapat End User tidak sama dengan pendapat Client. Misalnya, Client menginginkan suatu transaksi harus melalui approval supervisor, manager, dan direktur secara berjenjang. Tapi tentunya fitur ini akan memberatkan End User, karena ada banyak proses yang harus dilalui. Nah, tentunya Anda tahu siapa yang harus kita dengarkan. Nah, jadi kapan-kapan melakukan requirement development, cari tahu dulu siapa yang mengotorisasi bilyet giro :D

  • Konsultan Internal. Seringkali di organisasi client, ada seseorang yang cukup senior dari sisi teknis. Bisa jadi dia adalah divisi IT di organisasi client, atau orang luar yang dipercaya oleh client. Apakah orang ini harus kita dengarkan pendapatnya? Tergantung dari seberapa besar pengaruhnya terhadap client. Kita bisa mengetes pengaruhnya dengan membuat satu fitur yang tidak sesuai dengan pendapat konsultan internal ini, dan lihat apa reaksi client. Kalau client setuju dengan kita, berarti pengaruhnya tidak besar, dan pendapat selanjutnya bisa kita diabaikan.

  • Customer. Ada kalanya Client membeli aplikasi kita untuk dijual lagi ke orang lain. Nah orang lain ini disebut Customer. Sukses atau tidaknya project kita banyak ditentukan oleh berapa customer yang bisa didapatkan client. Jadi, penting juga untuk kita mengetahui profil customer (kalau ada). Apa business objective dari customer, sehingga bisa kita akomodasi dengan baik

Baiklah, saya sudah memetakan, si A adalah End User, si B Client, si C konsultan internal, dan si D adalah customernya. Apakah sekarang sudah bisa kita mulai interviewnya? Ok ok .. mari kita suruh Business Analyst (BA) untuk melakukan tugasnya. Oh, tunggu dulu, BA belum direkrut? Bagaimana kualifikasinya?

Kualifikasi Business Analyst

Pertama, BA harus menguasai proses bisnis. Kalau kita ingin membuat aplikasi akunting, BAnya harus mengerti akuntansi. Aturan sederhana dan logis, tapi masih banyak saja perusahaan yang mengirim programmer untuk melakukan requirement development.

Secara umum, BA harus sudah punya pengetahuan dasar dulu sebelum dia ketemu client. Kalau kita kirim programmer, maka dia bukan melakukan requirement development, tapi dia akan belajar bisnis proses ke client. Seperti kita akan lihat, ini pasti akan menimbulkan delay, karena :

Seorang BA harus bisa membedakan mana proses bisnis yang fundamental dan jarang berubah (karenanya boleh dihardcode), mana yang kondisional dan sering berubah (sehingga harus configurable)

Programmer yang belajar bisnis proses ke client tidak akan bisa membedakan ini. Sebagai contoh, mari kita lihat prosedur procurement.

Proses bisnis fundamentalnya adalah, ada pengajuan (purchase request), kemudian dilanjutkan dengan minta quotation ke vendor (request for quotation), memilih vendor, baru melakukan pemesanan (purchase order). Ini adalah flow fundamental, dan boleh di-hardcode.

Kemudian end user akan bilang, purchase request akan dilakukan oleh masing-masing dept, approval dilakukan manager, dst, dst. Siapa yang mengentri, siapa yang mengapprove, dan pada nilai transaksi berapa dia boleh approve, ini adalah kondisional dan harus bisa dikonfigurasi.

Nah, seorang BA yang baik harus bisa membedakan kedua hal ini.

Coba temani BA anda pada saat sesi interview dengan end user. Kalau dia pernah bilang begini,

Oh, di perusahaan Anda prosesnya begini ya? Biasanya yang umum dilakukan orang adalah seperti ini. Proses Anda kurang optimal karena blablabla. Apakah proses Anda mau berubah, atau aplikasi yang ingin ikut proses Anda dengan konsekuensi ABC?

Nah, kapan-kapan dia minta naik gaji, jangan buru-buru ditolak. Ini BA bagus. Dia menguasai bidangnya, dan tahu best practices.

Banyak perusahaan yang ingin bikin produk dari project tapi tidak kunjung berhasil. Misalnya, ada client minta dibuatkan aplikasi gudang, trus manajemen mikir, “Wah kayaknya ini kalo dibikin jadi produk bakalan prospek”. Tapi ternyata setelah project selesai, aplikasinya tidak applicable di perusahaan lain. Ini salah satu sebabnya adalah BA yang kurang pengalaman sehingga tidak tahu mana fitur yang generik berlaku umum dan mana yang spesifik hanya untuk perusahaan tertentu saja.

Tahu bisnis proses saja masih kurang, BA yang baik juga paham usability. Seperti kita tahu, ada banyak cara untuk mengentri transaksi. Bisa dientri via screen, bisa upload file, bisa via HP, bisa import dari aplikasi lain, dsb. BA yang baik bisa memberikan rekomendasi pada programmer mengenai user experience. Bagaimana urutan screen, penempatan komponen, apakah pilihan tertentu disajikan dengan dropdown, radio, atau lookup.

Kalau BAnya tidak paham usability, aplikasi kita akan benar secara proses bisnis, tapi tidak enak digunakan. Programmer tidak bisa menentukan usability, karena dia tidak tahu bagaimana biasanya end-user menggunakan fitur tertentu.

Ok, BA saya sudah canggih, paham bisnis proses, tau best practices, dan pernah magang sama Jakob Nielsen. Bisa kita mulai interview user?

Interview User

Pada fase ini, biarkan saja BA menjalankan tugasnya. Dia akan berbicara dengan user, dan menanyakan hal-hal berikut:

  • Flow global dari awal sampai akhir. Untuk aplikasi procurement, berarti dari request pembelian, sampai barang diterima.

  • Flow detail untuk masing-masing tahap. Contohnya, bagaimana detail flow proses request pembelian

  • Variasi skenario. Di sini BA akan mengidentifikasi percabangan dari tiap flow. Apa saja variasi skenarionya, perbedaan datanya, role user yang mengaksesnya, kondisi outputnya, dan sebagainya.

Jangan lupa untuk meminta :

  • Contoh report yang diinginkan

  • Sampel data transaksi untuk kita test di internal

  • Rumus atau formula perhitungan

Tergantung clientnya, ada kemungkinan dia akan meminta perjanjian kerahasiaan sebelum mengeluarkan data-data di atas.

Setelah interview, BA pulang ke kantor, dan akan membuat dokumentasi requirement.

Dokumentasi Requirement

Untuk apa kita membuat dokumentasi? Tujuannya adalah

  • Untuk mengidentifikasi kalau ada hal yang kurang jelas, sehingga bisa langsung ditanyakan

  • Sebagai bahan untuk verifikasi dengan user, apakah pemahaman kita sudah sama dengan yang dimaksud user.

  • Sebagai pedoman untuk programmer

  • Untuk mencegah project molor

Lho, bagaimana bisa dokumen requirement mencegah project molor? Ya bisa saja, berikut alasannya

  • Kalau ada kesalahan dan ditemukan pada fase ini, biaya perbaikannya jauh lebih kecil daripada kalau ditemukan pada fase coding. Misalnya ada kesalahan rumus perhitungan. Kalau kesalahan ini ditemukan pada fase requirement, paling biayanya cuma mengedit user story. Tapi kalau ditemukan pada waktu UAT, bisa-bisa butuh 2-3 hari untuk fixingnya. Ini katanya Steve McConnell, bukan bikin-bikinan saya.

  • Setelah requirement disign off, semua perubahan harus melalui change procedure. Ini mencegah project molor karena user terus menerus berubah pikiran. Sekarang maunya A, besok B, lusa ganti lagi.

Lalu, apa saja yang harus didokumentasikan? Daripada panjang lebar, silahkan lihat template User Story ArtiVisi. Di situ sudah kita siapkan form isian apa saja yang harus dicantumkan.

Coba lihat dulu, supaya nyambung dengan pembahasan di bawah.

Lho kenapa ada flow pengetesan? Apa bedanya dengan test scenario?

Sama saja, yang kita maksud flow pengetesan memang adalah test scenario. Lalu apakah wajib dibuat pada fase requirement? Kami sangat menganjurkan untuk membuatnya, dengan alasan sebagai berikut:

  • Dengan memikirkan bagaimana nanti pengetesannya, kualitas user story akan meningkat. BA terpaksa memikirkan step-by-step bagaimana aplikasi akan digunakan, apa inputnya, dan apa outputnya. Dengan memikirkan ini, semua variasi dan kebutuhan input, dan ekspektasi output mau tidak mau akan terpikirkan dan teridentifikasi sejak dini. Ini akan mengurangi requirement yang ambigu, tidak lengkap, atau tidak mungkin diimplementasikan

  • Test scenario yang ditandatangani user merupakan exit strategy bagi vendor. Kalau client sudah setuju dengan skenario testnya, maka vendor cukup membuat aplikasi yang lulus test tersebut. Setelah lulus test, jangan ditambah-tambahi lagi. Ini akan mencegah programmer menambah fitur-fitur menarik namun tidak memiliki business value.

Seperti bisa dilihat pada template, kita mengharuskan adanya screen prototype di dokumen requirement. Screen ini dirancang oleh BA (makanya dia harus paham usability), dan kalau mau, bisa dibuatkan dummy-nya. Dummy bisa dibuat dengan apapun teknologi yang murah dan cepat. Begitu desain screen jadi, seharusnya tidak lebih dari 2 jam waktu yang dibutuhkan untuk membuat dummy-nya, bahkan untuk screen kompleks sekalipun.

Yang harus ada di desain screen adalah :

  • Input field, harus jelas komponennya, apakah text, radio, dsb

  • Contoh isian. Jangan membuat input kosong, buatlah seolah-olah sudah diisi user. Ini akan memudahkan pada saat presentasi

  • Contoh output. Demikian juga dengan output hasil query, report, dsb. Jangan tampilkan tabel kosong. Isilah dengan data statis barang beberapa baris, agar user mempunyai gambaran bagaimana hasil akhirnya

Tidak perlu repot-repot mengimplementasikan dummy ini. Semuanya adalah data statis yang langsung diketik apa adanya.

Dokumen user story dan dummy dipresentasikan ke end user dan direvisi sesuai input. Pada fase ini, end user bebas membuat perubahan apapun yang diinginkan. Perubahan bebas untuk diakomodasi, asal jangan pernah melupakan siapa yang tandatangan otorisasi bilyet giro :D

Sign Off

Setelah semua user story diiterasi dengan end user sampai puas, maka tiba saatnya untuk melakukan feature-freeze. Semua dokumentasi requirement diupdate sehingga sesuai kondisi terakhir, lalu minta approval tertulis dari client. Ingatlah selalu, approval client, bukan end-user, bukan konsultan internal. Ini adalah aktivitas paling critical dan harus dilakukan. Segala usaha proses requirement akan percuma tanpa sign off client.

Change Management

Sebelum sign off, end user bebas mengajukan perubahan apapun. Setelah sign off, semua perubahan harus melalui change procedure. Intinya adalah, perubahan diajukan secara tertulis, diestimasi penambahan durasi dan costnya, lalu diajukan ke manajemen, baik vendor maupun client. Kalau salah satu pihak tidak setuju, maka perubahan tidak akan dijalankan.

Prosedur Change Management

Lebih jelas tentang informasi apa saja yang dibahas di change management, bisa melihat template change request ArtiVisi.

Seperti kita lihat, di sini faktor sign off sangat berperan. Tanpa ada sign off, tidak ada batas kapan user bisa berubah seenaknya, dan kapan tidak boleh.

Kalau change management dijalankan dengan baik, project akan lebih terkontrol. Walaupun ada kemunduran, kedua belah pihak sadar apa sebabnya. Semua perubahan diketahui manajemen, sehingga tidak ada bos yang tiba-tiba muncul dan bilang

Ini project kenapa gak beres-beres?

Kunci sukses change management adalah mulai dari awal, dan perhatikan hal kecil. Kita sebagai vendor sering mengabaikan prosedur ini dengan berbagai alasan, diantaranya

  • Ah perubahannya terlalu kecil, kalo langsung diimplement cuma 5 menit, tapi kalo change procedure bisa 2 hari.

  • Kita tidak mau terlihat birokratis seperti pegawai kelurahan perpanjang KTP

  • Kita berbaik hati pada client, masa perubahan sedikit saja hitung-hitungan banget

Ini merupakan kesalahan besar. Dengan memberlakukan change procedure bahkan untuk hal kecil, kita akan menimbulkan kesadaran di client bahwa kita mengelola project dengan ketat. Dengan demikian, mereka tidak sembarangan meminta perubahan. Client juga akan menyadari bahwa perubahan kecil saja akan berdampak pada keseluruhan project.

Kalau kita memang ingin berbaik hati pada client, silahkan digratiskan. Tapi prosedur tetap dijalankan. Jadi kalo tiba-tiba ada bos client yang tanya seperti di atas, tinggal kita sodori binder berisi daftar change request yang sudah diapprove.

Change procedure juga ada bonusnya, yaitu tidak banyak mengganggu programmer. Estimasi dan approval mostly dilakukan oleh business analyst dan project manager. Dan belum tentu juga client setuju. Kita akan menghemat banyak waktu, konsentrasi, dan pikiran programmer yang tidak perlu memikirkan usulan perubahan yang ternyata tidak disetujui.

Di change request juga ada timing kapan change akan diberlakukan. Untuk menjaga konsentrasi dan ritme tim, PM bisa menggunakan opsi ini untuk menunda change ke iterasi selanjutnya.

Requirement Traceability

Yang satu ini titipan dari CMMI. Di process area Requirement Management, CMMI mengharuskan adanya bidirectional traceability. Artinya, setiap hal di requirement harus bisa ditelusuri dokumen desain mana yang membahasnya, baris kode mana yang mengimplementasikannya, test scenario mana yang memverifikasinya. Demikian juga sebaliknya (makanya disebut bidirectional), setiap baris kode, harus bisa ditelusuri requirement mana yang membutuhkannya.

Ini ide yang bagus. Dengan melaksanakan ini, kita memastikan bahwa effort coding kita benar-benar efisien. Tidak ada effort terbuang percuma untuk fitur-fitur yang tidak perlu. Demikian juga sebaliknya, kita memastikan bahwa semua requirement sudah diimplementasikan dan tidak ada yang ketinggalan.

Walaupun demikian, ide bagus belum tentu realistis di lapangan. Saat ini di ArtiVisi, kita baru bisa merelasikan antara baris kode dengan requirement dengan menggunakan Trac. Tapi tidak untuk dokumen lainnya seperti user manual, test scenario, dsb. Dan itupun tidak bidirectional.

Kalau ingin tahu bagaimana ini diimplementasikan, silahkan lihat aplikasi ini.

Oh iya, kalau kita sudah melakukan semua anjuran di artikel ini, lengkap dengan Requirement Traceability, kita sudah siap untuk diaudit untuk proses area Requirement Management (Maturity Level 2) dan Requirement Development (Maturity Level 3) :D

Demikian penjelasan tentang fase requirement. Semoga bermanfaat.


Tips Melaporkan Error

Update 2011-12-02: karena masih aja banyak yang belum paham, saya tambahkan template pertanyaan di akhir artikel.

Sebagai programmer, setiap hari kita menghadapi software yang error. Bentuknya macam-macam, misalnya:

  • Aplikasi yang kita buat error

  • Peserta milis menggunakan framework X dan mengalami masalah

  • Rekan sesama programmer membutuhkan bantuan

  • dsb

Pada sebagian besar kasus, kita dengan senang hati akan membantu. Sudah menjadi sifat programmer untuk memiliki rasa keingintahuan yang tinggi dan senang terhadap teka-teki. Aplikasi yang error adalah teka-teki yang menarik.

Sayangnya, seringkali informasi error yang kita terima tidak lengkap sehingga butuh usaha tambahan untuk mengorek kejadian yang sebenarnya. Inilah yang membuat programmer seringkali keburu malas, sehingga akhirnya kegiatan solving error menjadi tidak fun lagi.

Berikut adalah beberapa tips untuk membuat laporan error yang baik, supaya programmer yang akan memecahkan masalah tersebut bisa segera bekerja dengan efektif.

Prinsip utama dalam melaporkan error adalah sebagai berikut

Programmer bukan Mama Loren Baby Djenar atau Ki Joko Bodo. Dia tidak bisa membaca pikiran ataupun melakukan telepati. Jadi jangan menganggap programmer melihat apa yang dilihat user. User harus menjelaskan apa yang dia lihat.

Jelaskan lokasinya

Seringkali si informan error berkata seperti ini,

Help, aplikasinya error nih

Nah, yang menerima informasi jelas bingung. Aplikasi yang mana? Kalo client yang jadi informan, bisa jadi kita punya banyak project di sana. Walaupun projectnya cuma satu, tapi aplikasi kan bisa terdiri dari banyak modul, screen, fitur, dsb.

Jadi, jelaskan di mana errornya. Di aplikasi apa, modul apa, screen yang mana. Terdengar simple, tapi nyatanya ada saja yang melewatkan hal pertama ini.

Mari kita lanjutkan.

Tujuan

Kita menggunakan aplikasi tentu ingin mencapai tujuan tertentu. Ingin menyimpan data customer, menampilkan laporan bulanan, dan lain sebagainya. Nah, tujuan ini harus disampaikan ke programmer. Soalnya sering terjadi percakapan seperti ini :

User (U) : Pak, fitur daftar produknya error.
Programmer (P) : Harusnya bisa kok, sudah kami test di sini tidak ada masalah.
U : Tapi saya coba tidak bisa
P : Coba jelaskan langkahnya
U : Saya buka menu daftar produk, muncul tabel berisi produk. Kemudian saya klik dua kali nama produk dalam tabel, saya ganti isinya. Setelah itu, saya tutup screennya. Pas dibuka lagi, datanya tetap sama.
P : Lho, memangnya Ibu mau melakukan apa?
U : Saya mau edit harga produknya
P : Walah, bukan dari situ Bu. Gunakan menu edit produk

Nah, seringkali tujuan user tidak sesuai dengan fitur aplikasi. Jadi, beri tahukan tujuan user pada programmer.

Langkah Reproduksi

Begitu programmer akan mencoba memperbaiki error, dia akan mencoba mereproduksi error tersebut di komputernya sendiri. Nah di sinilah biasanya terjadi percakapan seperti ini :

U : Ini aplikasi error, tidak bisa simpan data
P : Oh, di sini saya coba bisa kok
U : Di sini tidak bisa
P : Di sini bisa
U : Tidak bisa
P : Bisa
dst

Akan lebih produktif kalau percakapannya seperti ini :

U : Ini aplikasi error, tidak bisa simpan data
P : Apa yang dilakukan?

U : Seperti ini :

  1. Buka screen Edit Produk
  2. Pilih kategori Komputer dan Elektronik
  3. Isi kode produk
  4. Isi nama produk
  5. Harga dikosongkan
  6. Tekan tombol simpan

Nah, dengan percakapan seperti ini, programmer bisa mengulangi apa yang dilakukan user. Apakah langkah repro saja sudah cukup? Belum, masih ada 1 hal penting lainnya.

Harapan dan Kenyataan

Mari kita lanjutkan percakapan di atas.

U : Setelah ditekan tombol simpan, datanya tidak tersimpan.
P : Di tempat saya masuk kok ke database.
U : Di sini, setelah ditekan simpan tidak terjadi apa-apa
P : Maksudnya?
U : Ya harusnya kan ada pesan, “Data sudah tersimpan”
Ini tidak ada.

Nah, di sini harapan user adalah ada notifikasi dari aplikasi bahwa data sudah tersimpan. Tapi kenyataannya tidak ada notifikasi apa-apa dari aplikasi. User mengira ini error, padahal programmer memang tidak menyediakan notifikasi tersebut, walaupun datanya sudah masuk ke database. Dari sini, programmer bisa menambahkan notifikasi sesuai harapan user.

Jadi, harapan dan kenyataan harus disampaikan pada programmer.

Environment

Ini maksudnya adalah kondisi di mana aplikasi dijalankan, seperti

  • Sistem Operasi

  • Versi Aplikasi

  • Aplikasi lain yang terinstal

Sering terjadi aplikasi error hanya di Linux saja, atau di Mac saja, tapi berjalan lancar di Windows. Atau sebaliknya. Dengan memberi informasi ini, programmer bisa lebih terarah dalam mencari kesalahan dalam kode program.

Demikian juga dengan versi aplikasi dan aplikasi lain yang terinstal. Seringkali sudah diketahui bahwa aplikasi kita tidak kompatibel dengan versi library tertentu, versi OS tertentu, atau dengan aplikasi lain. Misalnya seperti ini :

Tanya (T) : Saya instal Tomcat tapi error
Jawab (J) : Errornya gimana?
T : Katanya port 8080 tidak bisa digunakan.
J : Apakah ada webserver lain yang terinstal?
T : Web server sih tidak ada, saya cuma install database Oracle saja.
J : Oh, Oracle itu membawa web server sendiri, jalannya juga di 8080.
Coba matikan Oraclenya, atau ganti port Tomcat ke angka lain.

Demikian beberapa tips melaporkan error.

Berikut ringkasannya :

  1. Jelaskan Lokasinya

  2. Sebutkan Tujuan

  3. Langkah Reproduksi

  4. Harapan dan Kenyataan

  5. Environment

Berikut template yang bisa digunakan untuk mengajukan pertanyaan.

Saya ingin …… (misal : mendeploy aplikasi di glassfish), untuk itu saya melakukan langkah2 berikut :

  1. ….
  2. ….
  3. ….

Setelah saya lakukan langkah di atas, saya mengharapkan hasil sbb:

  1. …..
  2. …..
  3. …..

Tapi ternyata kok malah muncul hasil seperti ini :

  1. ….
  2. ….
  3. ….

Sebagai tambahan informasi, saya menggunakan :

  1. Sistem Operasi … versi …
  2. Bahasa Pemrograman … versi …
  3. Database … versi …
  4. Framework/Tools … versi …

Dengan mengikuti tips ini berarti Anda sudah membantu kami untuk membantu Anda. :D


Dokumentasi Project

Pertanyaan yang sering muncul dalam pengelolaan proyek software adalah, “Dokumen apa saja yang harus dibuat?”

Tidak ada jawaban absolut untuk pertanyaan ini, semuanya tergantung situasi dan kondisi. Bahkan di satu perusahaan yang sama, kelengkapan dokumen projectnya bisa saja berbeda antar project.

Dalam artikel ini, kita akan membahas bagaimana menentukan dokumen yang digunakan dalam project.

Disclaimer : Semua yang dijelaskan pada artikel ini ditulis berdasarkan pengalaman dan kebutuhan internal ArtiVisi. Kebutuhan Anda belum tentu sama dengan kami.

Pertama, kita harus tahu dulu latar belakang kenapa dokumen project dibutuhkan. Setidaknya ada beberapa kegunaan dokumen project, yaitu

  • sebagai media komunikasi di internal tim, dengan client, dengan manajemen, dan pihak lain yang berkepentingan (stakeholder)

  • sebagai catatan historis jalannya project

  • sebagai alat bantu untuk melihat kondisi terkini project (project visibility)

  • sebagai kontrak legal bila terjadi perselisihan

Setelah kita mengetahui apa saja kegunaan dokumen, mari kita teliti satu persatu berdasarkan fase dalam project.

Fase Sales

Biasanya pada saat ada tawaran project, kita akan membuat proposal yang relatif tebal (> 10 halaman). Kami di ArtiVisi saat ini sudah hampir tidak pernah membuat proposal project, karena beberapa alasan berikut :

  • semakin tebal dokumen, semakin tidak dibaca

  • membuang effort percuma untuk membuat dan maintenance

Fungsi proposal sebenarnya adalah panduan awal untuk membuat agreement. Poin-poin yang ada di proposal akan dipindahkan ke agreement yang selanjutnya akan ditandatangani kedua belah pihak.

Kami menyederhanakan proposal menjadi quotation biasa, yang berisi informasi sbb :

  • scope pekerjaan

  • out of scope

  • estimasi durasi

  • requirement khusus (misalnya performance requirement, integrasi dengan aplikasi lain, dsb)

  • nilai project

  • termin pembayaran

Ada beberapa informasi yang biasa ada di proposal dan tidak ada di quotation, yaitu

  • teknologi yang digunakan. Biasanya client kami menurut saja apa solusi yang kita rekomendasikan. Kalaupun ada requirement khusus, akan ditulis di bagian requirement khusus di quotation

  • skema layer, tier, database diagram, dsb. Biasanya, implementasi internal aplikasi tidak perlu dipikirkan client. Client cukup menentukan what to be built, dan kami yang memikirkan how to build. Kalau client ingin ikut cawe-cawe urusan internal, biasanya kita tawarkan outsourcing programmer saja, bukan project software.

Selanjutnya, setelah quotation dinegosiasikan dan disetujui, tiba saatnya membuat agreement, atau perjanjian kerja sama. Ada beberapa poin yang dicantumkan dalam agreement, yaitu :

  • scope pekerjaan

  • out of scope

  • estimasi durasi

  • klausul keterlambatan delivery

  • termin pembayaran

  • klausul keterlambatan pembayaran

  • prosedur change management

Dari beberapa poin di atas, poin klausul keterlambatan delivery harus mendapat perhatian khusus. Keterlambatan delivery bisa terjadi karena banyak sekali sebab. Tidak semua diantaranya adalah kesalahan tim project. Oleh karena itu, kalau ada klausul seperti ini di agreement, tim project harus mengeluarkan effort ekstra untuk melakukan project tracking. Dengan demikian, bila terjadi keterlambatan, ada data yang lengkap mengenai riwayat dan penyebab keterlambatan tersebut.

Selesai bagian agreement, mari kita masuk ke tahap berikutnya.

Project Planning

Tujuan dari dilakukannya dokumentasi pada fase ini adalah untuk mengkomunikasikan bagaimana project akan berjalan, baik ke internal tim maupun ke client. Berikut informasi yang ada dalam project plan :

  • Milestone dan Delivery : list urutan delivery yang akan disampaikan, isi dari masing-masing delivery, dan estimasi tanggalnya

  • Daftar Task untuk Milestone berikut. Kita tidak melakukan breakdown untuk milestone lainnya, karena masih banyak ketidakpastiannya. Breakdown task hanya dilakukan untuk milestone yang ada di depan mata. Begitu suatu milestone akan selesai, baru dilakukan breakdown task untuk milestone selanjutnya.

  • Daftar Resiko Project : ini adalah hal-hal yang berpotensi menghambat jalannya project, seperti misalnya ada PIC client yang akan resign, teknologi yang belum familiar, dsb

Kami tidak membuat Gantt chart. Sebabnya karena Gantt chart sangat menekankan pada dependensi antar task. Sedangkan di project software, dependensi sangat mudah berubah. Misalnya, kita definisikan Modul B dikerjakan setelah Modul A. Ternyata karena PIC client di modul A sedang ada training di luar kota, diputuskan bahwa Modul B akan dikerjakan duluan. Atau, tadinya direncanakan skema database akan dikerjakan sebelum desain UI. Tapi ternyata karena satu dan lain hal, terpaksa UI dikerjakan duluan.

Hal-hal seperti ini cukup sering terjadi dalam project. Sehingga penggunaan Gantt chart justru akan merepotkan kita dalam mengupdate project plan. Kita tahu, semakin sulit dokumen diubah, semakin malas kita mengubahnya, dan akhirnya dokumen tersebut menjadi tidak up to date.

Project Tracking

Project tracking adalah kegiatan untuk memantau jalannya project. Dalam kegiatan ini, project manager melihat kemajuan project, mengidentifikasi masalah yang terjadi, dan mencarikan solusinya. Kalau masalah yang terjadi berada di luar kemampuan PM, dia akan melakukan eskalasi, yaitu meminta bantuan ke atasannya.

Di ArtiVisi, kita cuma menggunakan satu dokumen untuk melakukan project tracking, yaitu progress report mingguan, yang berisi informasi sbb:

  • Daftar task yang dikerjakan minggu ini dan statusnya, apakah sudah selesai, sedang dikerjakan, atau belum dimulai

  • Daftar task yang akan dikerjakan minggu depan

  • Daftar deliverable yang akan diberikan minggu depan

  • Resiko project saat ini. Daftar ini dibuat pada saat planning, terus menerus dipantau setiap minggu, dan dilaporkan statusnya

  • Masalah yang terjadi dalam project dan action plan yang dilakukan

  • Perubahan terhadap estimasi awal

Dokumen ini dibuat oleh PM setelah berkonsultasi dengan pasukannya, kemudian dikirim ke manajemen internal dan client. Dengan tidak adanya Gantt chart, kita tidak perlu mengeluarkan effort ekstra untuk mengupdate Gantt chart.

Fase Requirement

Pada fase ini, tim project menganalisa kebutuhan user sebagai patokan di fase coding. ArtiVisi cuma membuat satu dokumen pada fase ini, yaitu User Story. Dokumen user story berisi informasi sbb:

  • User Goal : tujuan yang ingin dicapai client dalam menggunakan fitur ini

  • Ijin Akses : security level untuk menjalankan fitur ini

  • Penjelasan : deskripsi naratif tentang fitur ini

  • Flow aplikasi : langkah-langkah untuk menjalankan fitur ini

  • Desain screen : screenshot prototype atau scan paper prototype

  • Rincian field : penjelasan masing-masing komponen dalam desain screen

  • Prasyarat : hal-hal yang harus terjadi/ada sebelum fitur ini bisa dijalankan

  • Kondisi awal : kondisi aplikasi (data, screen, dsb) sebelum fitur dijalankan

  • Kondisi akhir : kondisi aplikasi setelah fitur selesai dijalankan

  • Karakteristik khusus : kebutuhan khusus seperti response time, usability, dsb

  • Flow pengetesan : bagaimana cara mengetes fitur ini

  • Sign Off : persetujuan user bahwa deskripsi dalam fitur ini sudah sesuai keinginan

Nantinya akan ada banyak dokumen User Story sesuai jumlah fitur dalam aplikasi. Setelah User Story ditandatangani, semua perubahan harus melalui change procedure, yaitu dengan mengisi change request form. Berikut informasi yang ada di dalam change request form :

  • Penjelasan Perubahan : deskripsi dari apa saja yang ingin diubah

  • Alasan Perubahan : mengapa perubahan ini diajukan

  • Benefit : keuntungan bila perubahan diimplementasikan

  • Dampak : akibat terhadap durasi, effort, dokumen, source code bila perubahan jadi diimplementasikan

  • Estimasi : estimasi effort, durasi, cost untuk menjalankan perubahan ini

  • Approval : persetujuan manajemen baik kedua belah pihak terhadap perubahan ini

Fase Desain

Di fase desain biasanya kami mendesain beberapa hal berikut:

  • skema database

  • interkoneksi antar modul

  • protokol komunikasi

  • format data

Walaupun prosesnya dilakukan, tapi tidak ada dokumen permanen yang dihasilkan. Skema database misalnya. Desain dibuat di papan tulis, dan langsung ditulis dalam bentuk source code (SQL atau Hibernate mapping). Bila suatu saat diperlukan diagram, akan digenerate dengan tools dari database development. Protokol komunikasi dan format data akan dibuat di dokumen user story sebagai requirement internal.

Fase Coding

Pada fase ini, kita menghasilkan source code dan user manual.

Fase UAT

Pada fase ini, kita membuat dua dokumen, yaitu hasil pengetesan sesuai skenario di User Story dan Berita Acara UAT. Biasanya (tapi tidak selalu), berita acara dan hasil pengetesan digunakan sebagai lampiran penagihan.

Fase Implementasi

Pada fase ini, cuma satu dokumen yang dihasilkan, yaitu Berita Acara Serah Terima Aplikasi. Dokumen ini dibuat dan ditandatangani setelah kegiatan implementasi selesai dilakukan. Beberapa kegiatan dalam fase ini antara lain :

  • Instalasi Aplikasi

  • Training User

  • Deployment Aplikasi

  • Paralel Run

Demikian dokumentasi project yang kita buat selama project. Tidak terlalu banyak kan? Berikut daftarnya

  1. Quotation

  2. Agreement

  3. Project Plan

  4. Progress Report

  5. User Story

  6. Requirement Sign Off

  7. Change Request Form (kalau perlu)

  8. User Manual

  9. Berita Acara UAT

  10. Berita Acara Serah Terima Aplikasi

Kesimpulannya, buatlah dokumen sesuai kebutuhan, bukan sesuai hype yang sedang trend saat ini dan bukan juga sesuai warisan leluhur.