Topik ini merancang arsitektur proyek rekap nilai ujian sebelum kode implementasinya ditulis. Pembahasannya mencakup pembagian tanggung jawab antara modul dan skrip, struktur data utama, kontrak data setiap subrutin, serta antarmuka command line yang dijanjikan kepada pengguna. Setelah topik ini diikuti, setiap berkas proyek dapat ditulis secara terpisah karena tugas, bentuk data, dan antarmukanya sudah disepakati lebih dahulu.
Pembagian tanggung jawab modul dan skrip#
Arsitektur proyek ini membagi kode menjadi dua berkas dengan tugas yang tidak tercampur. Berkas RekapNilai.pm memuat seluruh logika, yaitu subrutin baca_data untuk membaca dan memvalidasi berkas data, hitung_rata untuk menghitung rata-rata sebuah array nilai, dan ringkas untuk menyusun statistik per siswa beserta statistik kelas. Berkas rekap.pl menjadi antarmuka command line, yaitu menerima argumen, memuat modul, memanggil subrutinnya, dan mencetak laporan. Pembagian ini mengikuti konvensi yang dijelaskan dokumentasi Perl, yaitu modul berisi kode yang dapat digunakan ulang, sedangkan skrip merupakan program yang memanggilnya.
Alasan utama pembagian ini adalah pengujian. Subrutin pada modul dapat dipanggil langsung dari berkas pengujian tanpa argumen command line dan tanpa memulai proses baru, sehingga perilaku setiap subrutin dapat dibandingkan dengan nilai harapan. Bila logika bercampur dengan pencetakan di dalam satu skrip, satu-satunya cara mengujinya adalah menjalankan skrip utuh lalu membaca keluarannya, dan cara itu rapuh serta sulit diotomatisasi. Modul yang murni mengolah dan mengembalikan data mudah diuji, sedangkan skrip yang dibuat tipis jarang memuat perilaku yang perlu diuji.
Struktur data utama#
Struktur data utama proyek ini adalah hash dari array, yaitu hash yang kuncinya nama siswa dan nilai tiap kuncinya berupa array berisi seluruh nilai milik siswa tersebut. Bentuk ini cocok dengan cara data dibaca, karena setiap baris berkas menyumbang satu nilai untuk satu kunci dan penambahan elemen array tidak memerlukan pencarian posisi. Struktur berikut memperlihatkan isinya untuk berkas contoh pada topik pemilihan proyek.
use strict;
use warnings;
use Data::Dumper;
# hash dari array: kunci berupa nama siswa, isinya array nilai
my %rekap = (
Ali => [ 80, 90 ],
Budi => [ 75, 65 ],
Citra => [88],
);
$Data::Dumper::Sortkeys = 1;
$Data::Dumper::Indent = 1;
print Dumper( \%rekap );$VAR1 = {
'Ali' => [
80,
90
],
'Budi' => [
75,
65
],
'Citra' => [
88
]
};Hash dipilih untuk menggantikan array dari hash yang menyimpan nama pada setiap elemennya. Pencarian nilai satu siswa pada hash langsung menuju kuncinya, sedangkan pada array pencarian tersebut harus menelusuri elemen satu per satu. Kebutuhan lain proyek ini hanya agregasi, sehingga struktur terdangkal seperti ini sudah cukup dan tidak perlu dibuat lebih dalam. Urutan kunci sendiri tidak menjadi bagian dari struktur, sebab urutan itu diatur ketika laporan dicetak, bukan ketika data disimpan.
Kontrak data antarsubrutin#
Kontrak subrutin menyatakan argumen yang diterima dan nilai balik yang dikembalikan. Kontrak ini ditetapkan sebelum kode ditulis karena seluruh pengujian pada implementasi nanti membandingkan nilai balik dengan ketentuan di sini. Untuk modul RekapNilai, kontraknya dinyatakan sebagai tabel berikut.
| Subrutin | Argumen | Nilai balik |
|---|---|---|
baca_data | Jalur berkas data | Referensi hash nilai per siswa, lalu jumlah baris tidak valid |
hitung_rata | Referensi array nilai | Rata-rata berupa satu angka, atau 0 untuk array kosong |
ringkas | Referensi hash nilai per siswa | Referensi hash berisi daftar siswa dan statistik kelas |
Bentuk nilai balik ringkas juga perlu disepakati sampai ke isinya, karena struktur itulah yang dibaca skrip saat menyusun laporan. Pada implementasinya, setiap argumen tiba di dalam subrutin melalui array @_, sehingga baris pertama setiap subrutin menyalin isinya ke variabel dengan nama yang jelas. Pengiriman referensi pada tabel di atas juga disengaja, karena array dan hash yang dikirim langsung diratakan menjadi satu daftar pada @_, sedangkan referensi tetap berupa satu nilai yang utuh. Contoh berikut membangun struktur tersebut dan menelusurinya seperti yang akan dilakukan skrip.
use strict;
use warnings;
# struktur yang dikembalikan ringkas: satu hash berisi dua kelompok informasi
my $ringkasan = {
siswa => [
{ nama => 'Ali', banyak => 2, rata => 85 },
{ nama => 'Budi', banyak => 2, rata => 70 },
],
tertinggi => 90,
terendah => 65,
rata_kelas => 77.5,
banyak_nilai => 4,
};
foreach my $s ( @{ $ringkasan->{siswa} } ) {
printf "%s: rata-rata %.2f dari %d nilai\n",
$s->{nama}, $s->{rata}, $s->{banyak};
}
printf "Kelas: tertinggi %d, terendah %d, rata-rata %.2f\n",
$ringkasan->{tertinggi}, $ringkasan->{terendah}, $ringkasan->{rata_kelas};Ali: rata-rata 85.00 dari 2 nilai
Budi: rata-rata 70.00 dari 2 nilai
Kelas: tertinggi 90, terendah 65, rata-rata 77.50Antarmuka command line#
Antarmuka command line adalah kontrak proyek dengan penggunanya, sehingga dirancang sebelum kode skrip ditulis. Proyek ini sengaja menggunakan bentuk paling sederhana, yaitu satu argumen posisi berupa jalur berkas data tanpa opsi tambahan. Menjalankan perl rekap.pl tanpa argumen membaca berkas bawaan nilaipercobaan.txt dari direktori kerja, sedangkan menjalankan perl rekap.pl nilaibermasalah.txt membaca berkas yang disebut. Bentuk ini cukup karena proyek hanya menerima satu masukan, dan penambahan opsi semacam --format baru dipertimbangkan bila kebutuhannya benar-benar muncul.
Perilaku program pada tiap keadaan juga menjadi bagian dari rancangan, termasuk kode keluar yang diserahkan kepada pemanggil. Kode keluar memungkinkan perintah lain, misalnya skrip pengotomatisasi, menilai keberhasilan program tanpa membaca isinya.
| Keadaan | Perilaku program | Kode keluar |
|---|---|---|
| Tanpa argumen | Membaca nilaipercobaan.txt dari direktori kerja | 0 pada data yang sah |
| Argumen berisi jalur berkas | Membaca berkas yang disebut | 0 pada data yang sah |
| Ada baris tidak valid | Pesan per baris ke STDERR, laporan tetap dicetak | 0 |
| Berkas tidak ada | Pesan error ke STDERR, lalu program berhenti | 2 |
| Tidak ada nilai yang sah | Pesan error ke STDERR, lalu program berhenti | 2 |
Angka 2 pada dua keadaan terakhir berasal dari nilai $! saat open gagal, yang dibawa die sebagai kode keluarnya. Kebijakan lengkapnya diwujudkan bersama kode implementasinya.
Diagram alur data#
Diagram berikut merangkum arsitektur yang sudah dirancang, yaitu alur dari berkas data menuju laporan melalui modul dan skrip.
Alurnya bergerak satu arah. Skrip mengimpor modul, modul membaca berkas data dan mengembalikan struktur data, lalu skrip mencetak laporan. Tidak ada jalur balik dari skrip ke modul maupun dari modul ke berkas data, sehingga setiap bagian dapat diperiksa secara terpisah. Modul diuji dengan berkas contoh tanpa menyentuh skrip, sedangkan skrip diperiksa dengan menjalankannya. Diagram juga menegaskan bahwa berkas data dan laporan berada di luar kedua berkas kode, sehingga perubahan format laporan hanya menyentuh skrip, sedangkan perubahan aturan validasi hanya menyentuh modul. Batas perubahan yang jelas semacam ini adalah manfaat arsitektur yang paling sering dirasakan ketika proyek berkembang.
Alur satu arah juga menjelaskan posisi berkas pengujian yang menyertai implementasi. Berkas uji mengimpor RekapNilai secara langsung, memanggil ketiga subrutinnya dengan data kecil, dan membandingkan nilai baliknya, tanpa menyentuh rekap.pl maupun laporannya. Kegagalan pengujian dengan demikian selalu menunjuk pada logika modul, bukan pada tampilan laporan.
Kesalahan umum#
- Logika ditulis di dalam skrip antarmuka sehingga subrutinnya tidak dapat diuji tanpa menjalankan seluruh program. Perbaikannya adalah memindahkan setiap subrutin yang mengolah data ke modul dan menyisakan penerimaan argumen serta pencetakan di skrip.
- Struktur data dibuat terlalu dalam, misalnya hash dari hash dari array, padahal kebutuhan proyek hanya agregasi sederhana. Perbaikannya adalah memilih struktur terdangkal yang memenuhi kebutuhan laporan, lalu mengembangkannya hanya bila kebutuhan baru muncul.
- Kontrak subrutin tidak dinyatakan secara tertulis, sehingga bentuk nilai baliknya berubah saat implementasi berjalan dan kode lain yang bergantung padanya ikut rusak. Perbaikannya adalah menetapkan argumen dan nilai balik setiap subrutin sebelum kode ditulis.
Ringkasan#
- Proyek dibagi menjadi modul logika
RekapNilai.pmdan skrip antarmukarekap.plagar logikanya dapat diuji terpisah dari antarmukanya. - Data utama berupa hash dari array dengan kunci nama siswa, dan urutan laporannya diatur saat pencetakan dengan
sort keys. - Setiap subrutin memiliki kontrak argumen dan nilai balik yang tertulis dan menjadi dasar pengujian.
- Antarmuka command line menggunakan satu argumen posisi dengan kebijakan perilaku dan kode keluar yang ditetapkan lebih dahulu.
Referensi#
- perlmod — dokumentasi resmi Perl — Aturan pembuatan modul, mulai dari package, nama berkas, hingga konvensi isinya.
- perldsc — dokumentasi resmi Perl — Resep struktur data kompleks, termasuk hash dari array yang digunakan proyek ini.
- perlref — dokumentasi resmi Perl — Aturan referensi yang menjadi fondasi struktur data bersarang dan nilai balik subrutin.