28 Dec 2006
Mengelola project software tidak mudah. Ada berbagai aspek teknis dan non teknis. Apalagi kalau projectnya berkaitan dengan pemerintahan atau organisasi lain yang birokratis. Akan banyak pekerjaan dokumentasi.
Di sisi lain, pekerjaan teknis selain coding juga tidak kalah banyaknya. Contohnya, dalam kehidupan sehari-hari programmer, dia harus:
- Menulis kode
- Menyimpan kode di repository
- Memberitahu programmer lain tentang perubahan yang dilakukan
- Menulis dokumentasi kode
- Menjalankan unit test
- Membuat rilis
- Menjawab pertanyaan client/bos/tim user manual
Semua kegiatan ini harus dikelola dengan baik agar tidak saling tumpang tindih. Untungnya banyak perangkat pembantu yang dapat memudahkan hidup kita. Pastikan Anda menggunakan persenjataan ini agar proyek bisa berjalan dengan lebih lancar. Berikut daftarnya:
- Version Control
- Bug tracker
- Mailing list
- File server
- Wiki
- Forum
- Build server
Mari kita bahas dengan lebih detail.
Version Control
Semacam file server, tapi lebih sakti. Mampu menyimpan riwayat perubahan, perbedaan antar versi, dan lainnya. Silahkan download presentasi saya tentang Subversion untuk pemahaman lebih lanjut.
Bug Tracker
Sepanjang perjalanan project, pasti banyak terjadi kesalahan. Baik kesalahan dokumen, kode program, permintaan yang kurang jelas, dan sebagainya. Daripada membuat mencatat di satu file khusus, lebih baik gunakan aplikasi bug tracker. Setiap entri di bug tracker bisa ditugaskan pada satu user. Status dari setiap entri (sedang dikerjakan, sudah selesai, selesai tapi tidak memuaskan) semua bisa ditentukan.
Gunakan bug tracker untuk memberikan tugas pada orang lain. Bug tracker yang baik biasanya terintegrasi dengan mail server, sehingga begitu kita membuat entri, email akan dikirim ke orang yang menerima tugas. Pada waktu suatu entri selesai dikerjakan dan statusnya diganti, email akan dikirim ke si pemberi tugas. Dengan demikian, tidak ada hal yang tercecer atau terlupakan.
Berikut daftar beberapa aplikasi bugtracker yang gratis dan open source:
Mailing List
Biasanya dalam project, kita akan sering mengirim email ke beberapa orang sekaligus. Misalnya pengumuman rilis, klarifikasi requirement, janji meeting, atau laporan kemajuan. Daripada mengetik banyak alamat sekaligus, lebih baik buat mailing list sesuai tujuan komunikasi. Buatlah mailing list untuk manajemen dan development. Segala pengumuman dan diskusi tentang manajemen proyek dikirim ke mailing list manajemen. Pembicaraan tentang pemrograman dilakukan di milis development.
Dengan demikian, selain tidak perlu mengetik alamat email satu persatu dan beresiko lupa, semua pembicaraan juga terekam secara kronologis.
Tidak mau repot menginstal aplikasi milis? Gunakan saja milis gratisan seperti YahooGroups atau GoogleGroups.
File Server
Selain melalui repository, kadang kita perlu bertukar file berukuran besar. Untuk itu, kita perlu file server. Banyak penyedia file server gratisan di internet, misalnya Rapidshare atau Megaupload.
Kalau tidak mau pakai gratisan –mungkin takut data penting diambil orang– gunakan XAMPP.
Wiki
Wiki adalah website yang bisa diedit orang banyak. Contohnya wiki ArtiVisi. Cara mengeditnya juga mudah dan sederhana. Tidak perlu keahlian HTML atau pemrograman web. Ideal digunakan untuk membuat dokumen yang sering berubah dan diakses sepanjang waktu, misalnya:
- spesifikasi aplikasi
- desain sistem
- manual penggunaan aplikasi
Aplikasi wiki banyak tersedia secara gratis, misalnya:
dan masih banyak aplikasi lainnya.
Perbandingan antar aplikasi dapat dilihat di situs MediaWiki dan DokuWiki
Instalasi DokuWiki sangat mudah, cukup extract, kemudian publish melalui webserver yang support PHP. Pengguna Windows bisa menggunakan XAMPP dan menjalankan DokuWiki dalam 5 (lima) menit saja.
Forum
Apabila proyek/produk kita digunakan masyarakat luas, pasti akan banyak interaksi dengan pengguna. Biasanya pengguna baru akan menemui kesulitan dan butuh tempat bertanya. Mereka ini biasanya malas ikut milis, karena mungkin cuma butuh satu jawaban dan tidak ingin mengikuti diskusi di milis.
Kita bisa gunakan aplikasi forum yang banyak tersedia secara gratis. Salah satu yang terkenal adalah phpBB. Maniak Java bisa gunakan mvnforum.
Build Server
Apabila proyek kita sudah dilengkapi dengan version control, automated unit test, dan automated code review, kita bisa gunakan build server. Gunanya adalah agar secara berkala (misalnya sehari sekali), ada yang mengambil semua kode terbaru dari repository, melakukan kompilasi, menjalankan semua automated test, dan melaporkan hasilnya via website, email, rss, instant messenger, sms, atau media komunikasi lainnya.
Berkat keajaiban open source, aplikasi ini tersedia secara gratis. Kita bisa gunakan CruiseControl atau Luntbuild. Buat yang nekat tetap ingin bayar, bisa gunakan Pulse atau Bamboo.
Wow … begitu banyak yang harus disiapkan?
Begitu dalam pikiran Anda.
Jangan khawatir, ada aplikasi gratis untuk menyatukan semuanya. Gunakan Trac.
Bagaimana kalo projectnya banyak? Di kantor saya biasanya ada 10 project jalan berbarengan. Belum lagi 15 produk yang harus dikelola.
Jangan khawatir. Bawa pulang Sourceforge ke kantor Anda. Atau gunakan saingannya, GForge. Keduanya gratis dan open source.
Demikianlah rangkaian persenjataan dalam mengelola proyek. Semoga bermanfaat.
08 Dec 2006
Ide orang memang ada-ada saja. Kali ini ada situs yang menampilkan preview dari suatu link. Coba arahkan (tidak perlu klik) mouse anda ke link Snap.com ini. Tunggu sejenak, dan (tergantung kecepatan bandwidth anda) screenshot website Snap akan muncul.
Cara mendapatkannya tidak sulit. Cukup buka halaman pendaftarannya, dan masukkan:
- URL website kita
- Email
- Tulisan di gambar captcha
Centang I Agree dan klik Get Code.
Pada halaman berikutnya kita akan mendapat sepotong kode untuk dipasang di kode HTML website kita. Sangat mudah.
Selain Snap.Com, ada lagi website yang namanya Twitter. Kalau yang ini benar-benar kurang kerjaan. Silahkan cek sendiri dan cari tahu apa yang dikerjakan dunia saat ini.
01 Dec 2006
Setelah beberapa seri artikel Ruthless Testing, ternyata lebih banyak yang skeptis daripada yang antusias. Respon yang paling banyak ditemukan adalah:
Wah, ini konsep yang sangat menarik. Tentunya akan sangat baik jika diterapkan. Sayang sekali, di tempat saya tidak bisa, karena … [berbagai alasan dan kesulitan] …
Hmm … saya mengerti perasaan Anda. Been there, done that. Saya pernah jadi programmer, dan juga pernah jadi project manager. Saya mengerti beberapa keberatan dan kesulitan implementasinya.
Daripada berkeluh kesah tiada guna, mari kita lihat satu persatu masalahnya.
Programmer : Bikin unit test? Nambah kerjaan aja. Lagian test code kan gak dideliver ke client
Jawaban saya:
Unit test itu adalah investasi Anda. Bayangkan beberapa bulan/tahun yang akan datang, client datang ke kita, meminta perbaikan untuk error dalam aplikasi. Padahal kita sedang sibuk mengerjakan proyek lain yang sama sekali berbeda. Hampir seluruh kode sudah kita lupakan. Bahkan untuk method sederhana seperti ini
kita sudah lupa bagaimana behaviournya kalau menghadapi pembagian dengan nol, bilangan negatif, atau bilangan tidak bulat. Dan seperti biasa, kita tidak membuat komentar Javadoc.
Unit test to the rescue. Tinggal buka unit test untuk kode di atas, dan kita akan melihat bagaimana kode tersebut menghadapi bilangan negatif, nol, dan kasus-kasus aneh lainnya.
Next ..
Programmer : Aplikasi saya mengakses jaringan/database/email. Sulit dites
Jawaban saya:
Itu namanya integration testing, bukan unit testing. Walaupun demikian, tetap bisa dites secara otomatis. Tapi butuh sedikit investasi tambahan.
Misalnya, kita punya method seperti ini:
public void process(Order order) {
// coba lihat customernya, periksa saldonya
Customer c = order.getCustomer();
if(c.getBalance() < 0) {
// handle error
}
// saldo ok, simpan order ke database
String sql = "INSERT INTO tbl_order VALUES (?, ?, ?)";
// kirim email konfirmasi
String dest = c.getEmail();
// kode send email tidak ditunjukkan
}
Seperti kita lihat, ada beberapa integration point di sini, yaitu akses database dan koneksi ke mail server.
Untuk mengotomasi pengetesan method ini, kita gunakan teknik yang sudah teruji dari 400 tahun lalu: divide et impera. Yang tidak tidur di kelas waktu pelajaran Sejarah pasti tau teknik ini.
Sekarang teknik ini sudah diadaptasi ke dunia programming dengan istilah Refactoring. Silahkan google keyword tersebut untuk lebih jelasnya.
Pada contoh kita di atas, kita me-refactor kode akses database dan koneksi mail server ke class yang berbeda. Kita pisahkan kode tersebut ke class tersendiri. Berikut adalah interfacenya:
public interface OrderDao {
public void save(Order o);
}
dan
public interface MailSender {
public void send(String from, String to, String message);
}
Implementasinya disisakan buat latihan di rumah.
Sehingga method kita menjadi seperti ini:
public void process(Order order) {
// coba lihat customernya, periksa saldonya
Customer c = order.getCustomer();
if(c.getBalance() < 0) {
// handle error
}
orderDao.save(order);
mailSender.send(adminEmail, c.getEmail(), "Order sudah dikirim");
}
Dengan adanya kedua class tambahan ini, kita bisa menggunakan Mock Object untuk memalsukan object orderDao dan mailSender. Kita bisa buat kedua object ini selalu sukses, atau selalu gagal, tergantung skenario yang mau dites.
OrderDao sendiri bisa dites dengan menggunakan teknik pengetesan database. MailSender dapat ditest dengan menggunakan Dumbster, mail server palsu.
Kasus seperti ini biasanya terjadi karena kodenya sudah terlanjur campur aduk. Apabila unit test diterapkan dari awal project, programmer terkondisi untuk membuat kode yang mudah dites, sehingga effort untuk refactor tidak terlalu besar.
Tujuan utama kita adalah semua tes bisa dijalankan otomatis, independen (tes satu tidak mempengaruhi tes lain) dan repeatable(bisa diulang-ulang dengan hasil yang konsisten).
Tidak harus menggunakan JUnit. Bisa pakai tools buatan sendiri.
Keberatan berikutnya datang dari project manager.
Project Manager : Berarti saya harus alokasikan waktu tambahan untuk membuat unit test, wah bisa-bisa saya dimarahi client/bos.
Jawaban saya:
Bos… programmer Anda pasti membuat kode test, walaupun tidak otomatis. Ini sudah naluri dasar manusia.
Berikut contohnya:
public void process(Order order) {
// coba lihat customernya, periksa saldonya
// saldo ok, simpan order ke database
String sql = "INSERT INTO tbl_order VALUES (?, ?, ?)";
// coba periksa ... nanti kita hapus lagi
String coba = "SELECT * FROM tbl_order WHERE .. ";
// kirim email konfirmasi
String dest = c.getEmail();
// kode send email tidak ditunjukkan
}
Jadi, daripada dia pasang kode test di kode program, dan nantinya dihapus lagi, kan sayang. Lebih baik suruh saja untuk bikin unit test betulan.
Keuntungan berikutnya, dengan banyaknya unit test, kesalahan coding akan lebih cepat ditemukan, sehingga pada tahap testing oleh client, lebih sedikit bug yang ditemukan.
Dengan demikian, alokasi waktu untuk rework akan lebih sedikit.
Project Manager : Kalau terlalu banyak unit test, nanti aplikasinya menjadi rumit.
Jawaban saya:
Justru sebaliknya. Aplikasi yang banyak unit testnya akan menjadi lebih modular dan tidak terlalu kusut struktur internalnya. Dengan demikian, kode program menjadi lebih mudah dipelihara dan dikembangkan.
Terakhir, ada beberapa tips dari saya agar penerapan unit testing dapat berjalan dengan optimal:
- siapkan infrastruktur sebelum mulai coding
- sering-sering refactor agar kode mudah dites
- gunakan coverage testing sebagai pelengkap, agar kekurangan unit test cepat terdeteksi
- terapkan daily build otomatis yang menjalankan semua tes
Demikian, semoga bermanfaat
29 Nov 2006
Hari Sabtu, 2 Desember 2006 pukul 10.00 WIB, saya akan memberikan presentasi tentang Subversion di pertemuan rutin programmer Java (JaMU - Java Meet Up).
Adapun tempat kejadian presentasi (TKP) beralamat di:
SUN Microsystem Indonesia
Lantai 13, Gedung Wisma Metropolitan I (WTC Sudirman)
Jakarta
Subversion adalah aplikasi version control. Aplikasi ini mirip dengan file server, artinya dia bisa digunakan untuk menyimpan file, dan bisa diakses jika ingin mengambil file tersebut.
Bedanya dengan file server biasa (FTP server, Samba, atau Windows Sharing), aplikasi version control menyimpan riwayat perubahan semua yang kita simpan di dalamnya.
Kalau kita menyimpan satu file, kemudian isinya kita modifikasi (tambah baris, hapus, ganti nama, dan sebagainya), maka setiap perubahan tersebut dicatat oleh version control.
Tidak hanya dicatat, kita juga bisa mengembalikan kondisi file sesuai keinginan. Kita bisa melihat versi awal dari file tersebut, atau nama file sebelum diganti, dan semua titik penting lain di masa lalu.
Singkatnya, dalam urusan menyimpan file, version control mirip dengan mesin waktu.
SIlahkan datang ke JaMU minggu ini. Gratis, tidak dipungut biaya.
Materi yang akan dibawakan adalah:
- Konsep Version Control
- Penggunaan sehari-hari
- Tag, Branch, Merge
- Aplikasi pelengkap
- Keterbatasan Subversion
- Aplikasi sejenis (kompetitor)
Presentasi dapat didownload [di sini [PDF |
710KB]](http://endy.artivisi.com/downloads/writings/Subversion-presentation-20061129.pdf “Presentasi Subversion”). |
05 Oct 2006
Beberapa waktu yang lalu, ada posting menarik tentang Google yang menggunakan BerkeleyDB untuk mengelola user accountnya. Karena penasaran, saya lalu mencoba mendownload dan bermain-main dengan BerkeleyDB versi Java (Java Edition).
BerkeleyDB adalah produk embedded database open source yang populer. Belum lama ini dia diakuisisi oleh Oracle, sehingga membuat produk ini makin terkenal lagi.
Pada tulisan kali ini, kita akan mencoba menggunakan BDB Java Edition.
Tapi jangan salah paham dengan namanya. BerkeleyDB adalah database, tapi bukan relational database. Artinya, dia tidak memiliki fasilitas SQL. Walaupun demikian, dia mendukung ACID transaction. Salah satu contoh penggunaan BDB adalah pada aplikasi version control Subversion.
Kalau tidak ada SQLnya, bagaimana kita melakukan operasi CRUD? Jawabnya adalah, anggap saja BDB sebagai Map. Kita bisa menggunakan Map seperti ini:
Map myMap = new HashMap();
myMap.put(1, "Endy");
Maka object String akan disimpan dengan key 1. Object ini dapat diambil dengan kode:
String data = myMap.get(1);
Bagi mereka yang sudah pernah mendengar Object Database tentunya sudah familiar dengan konsep seperti ini. Salah satu implementasi konsep ini adalah db40 atau Prevayler.
Sekarang, coba kita gunakan contoh kasus yang standar. Ada class Person yang akan kita buatkan operasi CRUD-nya. Berikut kodenya:
Person.java
package tutorial.berkeleydb;
import java.util.Date;
import com.sleepycat.persist.model.Entity;
import com.sleepycat.persist.model.PrimaryKey;
@Entity
public class Person {
@PrimaryKey(sequence="ID")
private Integer id;
private String name;
private Date birthdate;
private String email;
public Person(){
}
public String getEmail() {
return email;
}
public void setEmail(String address) {
this.email = address;
}
public Date getBirthdate() {
return birthdate;
}
public void setBirthdate(Date birthdate) {
this.birthdate = birthdate;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Perhatikan bahwa untuk menjadikan class Person persistent, kita hanya perlu menambahkan annotation, mirip dengan JPA atau Hibernate. Sekarang mari kita definisikan interface CRUD-nya.
PersonDao.java
package tutorial.berkeleydb;
import java.util.List;
public interface PersonDao {
public void save(Person p);
public void delete(Person p);
public Person getById(Integer id);
public List<Person> getAll();
}
Dan berikut adalah implementasinya.
PersonDaoBerkeleyDB
package tutorial.berkeleydb;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.persist.EntityCursor;
import com.sleepycat.persist.EntityStore;
import com.sleepycat.persist.PrimaryIndex;
public class PersonDaoBerkeleyDB implements PersonDao {
private PrimaryIndex<Integer, Person> personPrimaryKey;
public PersonDaoBerkeleyDB(EntityStore storage) {
try {
personPrimaryKey = storage.getPrimaryIndex(Integer.class, Person.class);
} catch (DatabaseException e) {
e.printStackTrace();
}
}
public void delete(Person p) {
try {
personPrimaryKey.delete(p.getId());
} catch (DatabaseException e) {
e.printStackTrace();
}
}
public List<Person> getAll() {
List<Person> result = new ArrayList<Person>();
try {
EntityCursor<Person> allPerson = personPrimaryKey.entities();
Iterator<Person> iter = allPerson.iterator();
while (iter.hasNext()) {
result.add(iter.next());
}
allPerson.close();
} catch (DatabaseException e) {
e.printStackTrace();
}
return result;
}
public Person getById(Integer id) {
try {
return personPrimaryKey.get(id);
} catch (DatabaseException e) {
e.printStackTrace();
}
return null;
}
public void save(Person p) {
try {
personPrimaryKey.put(p);
} catch (DatabaseException e) {
e.printStackTrace();
}
}
}
Sebagai perbandingan, berikut kode CRUD menggunakan Hibernate dengan bantuan Spring.
public class PersonDaoHibernate extends HibernateDaoSupport implements PersonDao{
public void save(Person p){
getHibernateTemplate().save(p);
}
public void delete(Person p){
getHibernateTemplate().delete(p);
}
public Person getById(Integer id){
Person result = null;
try {
result = (Person) getHibernateTemplate().load(Person.class, id);
getHibernateTemplate().initialize(result);
} catch (ObjectRetrievalFailureException e) {
log.log(Level.WARNING, "no object with id:"+id+" in database");
}
return result;
}
public List<Person> getAll(){
return getHibernateTemplate().find("from Person p");
}
}
Oh iya, contoh kode BDB di atas dapat diujicoba dengan membuat Main class sebagai berikut:
Main.java
package tutorial.berkeleydb;
import java.io.File;
public class Main {
private static EntityStore store;
private static Environment env;
public static void main(String[] args) throws Exception {
openDatabase();
Person endy = new Person();
endy.setName("Endy Muhardin");
endy.setBirthdate(new SimpleDateFormat("dd-MM-yyyy").parse("17-08-1945"));
endy.setEmail("endymuhardin@yahoo.com");
PersonDao dao = new PersonDaoBerkeleyDB(store);
dao.save(endy);
System.out.println("======== Create one person with ID:"+endy.getId()+" ========");
System.out.println("======== Display all person from database ========");
List<Person> all = dao.getAll();
for (Person person : all) {
displayPerson(person);
}
System.out.println("======== Add one more person to database ========");
Person khalisa = new Person();
khalisa.setName("Khalisa Alayya");
khalisa.setBirthdate(new SimpleDateFormat("dd-MM-yyyy").parse("31-12-2000"));
khalisa.setEmail("me@khalisa.web.id");
dao.save(khalisa);
System.out.println("======== Display all person from database ========");
all = dao.getAll();
for (Person person : all) {
displayPerson(person);
}
System.out.println("======== Get person by ID "+endy.getId()+" from database ========");
Person endyFromDb = dao.getById(endy.getId());
displayPerson(endyFromDb);
System.out.println("======== Change person data with ID "+endy.getId()+" from database ========");
endyFromDb.setEmail("endy.muhardin@gmail.com");
dao.save(endyFromDb);
System.out.println("======== Display person with ID "+endy.getId()+" after update ========");
Person endyFromDb2 = dao.getById(endy.getId());
displayPerson(endyFromDb2);
closeDatabase();
}
private static void displayPerson(Person person) {
System.out.println("ID : "+person.getId());
System.out.println("Name : "+person.getName());
System.out.println("Birthdate : "+person.getBirthdate());
System.out.println("Address : "+person.getEmail());
}
private static void openDatabase(){
try {
EnvironmentConfig config = new EnvironmentConfig();
config.setAllowCreate(true);
config.setTransactional(true);
env = new Environment(new File("database"), config);
StoreConfig storeConfig = new StoreConfig();
storeConfig.setAllowCreate(true);
storeConfig.setTransactional(true);
store = new EntityStore(env, "PersonDatabase", storeConfig);
} catch (DatabaseException e) {
e.printStackTrace();
}
}
private static void closeDatabase() {
try {
store.close();
env.close();
} catch (DatabaseException e) {
e.printStackTrace();
}
}
}
Selain contoh kode yang ditampilkan di sini, sebetulnya BDB juga mendukung asosiasi One to One, One to Many, dan Many to Many. Sayang sekali saya belum sempat coba.
Dari percobaan sederhana ini, kita dapat menarik beberapa sisi positif dan negatif dari BerkeleyDB, juga kemungkinan kasus yang tepat dan tidak tepat untuk menggunakan BDB.
Positif
- Ukuran jar kecil. Hanya butuh 1.1 MB untuk jar-nya BDB. Bandingkan jika kita gunakan MySQL + Hibernate. Jar mysql-connector 430KB, hibernate.jar 2MB, hibernate-annotation.jar 300KB, dependensi lainnya seperti ehcache, jta, cglib, asm, dan lainnya bisa mencapai 7MB total.
- Tidak perlu berkutat dengan SQL. Object oriented 100%
- Karena embedded, sangat cepat. Akses data instan langsung ke sumbernya. Bandingkan dengan rantai MySQL-network-hibernate-spring-aplikasi. Bagaikan langit dan bumi.
Negatif
- Karena embedded, sulit dimanipulasi dengan tools lain. Berbeda dengan database RDBMS yang bisa diakses menggunakan command line, web-based interface, atau database management tools.
- Karena tidak support SQL, tidak bisa dimanipulasi aplikasi lainnya. Misalnya aplikasi reporting.
- Untuk sharing data dengan aplikasi lain, kita harus buatkan API via Java atau XML.
- BDB mengandalkan Serialization untuk menyimpan object ke dalam database. Siapapun yang sudah pernah belajar Serialization pasti tahu bahwa penyakitnya ada pada class evolution. Kalau class kita berubah –misalnya menambah atau mengurangi field, apalagi rename class– BDB akan bingung, dan kita harus menulis kode program untuk melakukan migrasi.
Kapan menggunakan BDB
- Data yang disimpan hanya digunakan sendiri. Misalnya penyimpanan data session HTTP, cache untuk username dan password, dsb.
- Butuh kecepatan extra tinggi dan pemrograman yang mudah. Misalnya kita membuat server SMS gateway atau message processing. Butuh kecepatan tinggi, dan datanya kecil kemungkinan digunakan aplikasi lain.
- Anda termasuk orang yang living on the edge. Selalu menggunakan tools yang aneh dan terbaru.
Kapan menggunakan RDBMS
- Data harus bisa diakses aplikasi lain seperti reporting.
- Data berjumlah besar, sehingga sulit untuk dimigrasi apabila terjadi refactoring. (Ingat masalah Serialization)
- Perusahaan sudah terlanjur beli Oracle atau DB2.
Demikianlah .. semoga bermanfaat.
:D