Membangun Proyek Pemrograman
Dari ide sederhana menjadi program yang dapat digunakan. Pelajari cara merencanakan, merancang, menulis kode, menguji, dan mengembangkan proyek pemrograman menggunakan C++.
Selama mempelajari C++, kita telah mengenal berbagai konsep pemrograman. Kita sudah belajar menggunakan variabel, menerima input, membuat keputusan, mengulang instruksi, mengelola banyak data, menyusun fungsi, memahami pointer, mengenal pemrograman berorientasi objek, hingga mengolah file.
Namun, mempelajari setiap konsep secara terpisah belum tentu membuat kita langsung mampu membangun sebuah program yang utuh.
Bayangkan kamu diminta membuat aplikasi sederhana untuk mengelola data nilai murid di sebuah kelas. Program tersebut harus dapat menerima nama murid, menyimpan nilai, menghitung rata-rata, menentukan nilai tertinggi, dan menyimpan hasilnya agar dapat dibuka kembali.
Apakah kita cukup menulis beberapa baris kode lalu selesai? Tidak sesederhana itu.
Kita perlu menentukan masalah yang ingin diselesaikan, merancang fitur, menyusun alur kerja, memilih cara menyimpan data, menulis kode secara terstruktur, kemudian menguji apakah seluruh fitur berjalan sesuai kebutuhan.
Apa yang akan dipelajari?
Dalam pembahasan ini, kita akan mengikuti proses membangun sebuah proyek pemrograman dari awal hingga selesai. Contoh proyek yang digunakan adalah Program Pengelolaan Nilai Murid berbasis C++.
Proyek ini akan menjadi latihan untuk menggabungkan berbagai konsep yang telah dipelajari sebelumnya.
1. Proyek Pemrograman Dimulai dari Sebuah Masalah
Ketika seseorang ingin membuat program, langkah pertama seharusnya bukan langsung membuka editor kode dan mulai mengetik.
Langkah pertama adalah memahami masalah yang ingin diselesaikan.
Misalnya, seorang guru memiliki banyak data nilai murid. Selama ini, nilai dicatat secara manual di kertas atau spreadsheet. Ketika ingin menghitung rata-rata kelas, mencari nilai tertinggi, atau memeriksa nilai seorang murid, guru harus melakukan beberapa langkah secara berulang.
Dari situ muncul sebuah kebutuhan: bagaimana jika dibuat program sederhana yang dapat membantu mengelola data nilai tersebut?
Identifikasi masalah
Program dibutuhkan untuk membantu pengelolaan nilai murid agar proses pencatatan, perhitungan, pencarian, dan penyimpanan data menjadi lebih mudah.
Perhatikan bahwa kita belum membicarakan bahasa pemrograman, variabel, atau fungsi. Kita baru menentukan masalah yang ingin diselesaikan.
Hal ini penting karena program dibuat untuk memenuhi kebutuhan tertentu. Jika masalahnya belum dipahami, fitur yang dibuat bisa saja tidak sesuai dengan kebutuhan pengguna.
Menentukan tujuan proyek
Setelah masalah ditemukan, kita perlu menentukan tujuan proyek. Tujuan ini menjadi acuan agar proses pengembangan tidak melebar ke mana-mana.
Tujuan proyek pengelolaan nilai
(- ) Membantu pengguna memasukkan data nama dan nilai murid.
(- ) Menampilkan seluruh data yang sudah dimasukkan.
(- ) Menghitung rata-rata nilai.
(- ) Menentukan nilai tertinggi dan terendah.
(- ) Mencari data murid berdasarkan nama.
(- ) Menyimpan data ke dalam file agar tidak hilang ketika program ditutup.
Daftar tersebut sudah memberikan gambaran tentang apa yang harus dapat dilakukan oleh program.
2. Menentukan Fitur dan Batasan Proyek
Setelah mengetahui tujuan proyek, kita perlu menentukan fitur yang akan dibuat.
Fitur adalah kemampuan atau fungsi tertentu yang disediakan oleh program untuk membantu pengguna melakukan suatu pekerjaan.
Misalnya, program pengelolaan nilai memiliki fitur tambah data, tampilkan data, hitung statistik, cari data, dan simpan data.
Namun, ada satu hal yang perlu diperhatikan: proyek pertama tidak harus memiliki semua fitur yang mungkin dibayangkan.
Jika kita langsung mencoba membuat aplikasi yang terlalu besar, proses pengembangannya akan menjadi lebih sulit. Kita dapat menghabiskan banyak waktu untuk fitur tambahan sebelum fitur utamanya benar-benar berjalan.
Menentukan ruang lingkup proyek
Ruang lingkup atau scope adalah batasan mengenai apa saja yang akan dikerjakan dalam sebuah proyek.
Untuk proyek latihan ini, kita membatasi program pada pengelolaan nilai dalam satu kelas menggunakan aplikasi berbasis teks atau console.
| Fitur | Keterangan | Prioritas |
|---|---|---|
| Tambah data | Memasukkan nama dan nilai murid. | Utama |
| Tampilkan data | Menampilkan seluruh data. | Utama |
| Statistik nilai | Menghitung rata-rata, tertinggi, dan terendah. | Utama |
| Pencarian | Mencari data berdasarkan nama. | Utama |
| Penyimpanan file | Menyimpan dan membaca kembali data. | Utama |
| Login pengguna | Menggunakan akun untuk mengakses program. | Pengembangan |
| Grafik nilai | Menampilkan statistik dalam bentuk grafik. | Pengembangan |
Dengan pembagian tersebut, kita mengetahui mana fitur yang harus diselesaikan terlebih dahulu dan mana yang dapat dikembangkan setelah program utama berjalan.
Mengapa proyek perlu memiliki batasan?
Tanpa batasan, sebuah proyek dapat terus berkembang karena selalu muncul ide fitur baru.
Akibatnya, program mungkin tidak pernah selesai. Dalam pengembangan perangkat lunak, menyelesaikan versi sederhana yang benar-benar berfungsi sering kali lebih bermanfaat daripada merencanakan aplikasi besar yang tidak pernah selesai dibuat.
Setelah versi awal berjalan dengan baik, fitur baru dapat ditambahkan secara bertahap.
3. Merancang Alur Kerja Program
Setelah fitur ditentukan, kita perlu merancang bagaimana pengguna akan berinteraksi dengan program.
Bayangkan pengguna menjalankan program. Apa yang pertama kali ditampilkan? Bagaimana pengguna memilih fitur? Apa yang terjadi setelah pengguna memasukkan data?
Program yang baik memiliki alur yang jelas sehingga pengguna tidak kebingungan.
Membuat menu utama
Untuk proyek pengelolaan nilai, kita dapat menyediakan menu utama seperti berikut:
================================
PROGRAM PENGELOLAAN NILAI
================================
1. Tambah Data Murid
2. Tampilkan Semua Data
3. Hitung Statistik Nilai
4. Cari Data Murid
5. Simpan Data
6. Keluar
================================
Pilih menu: _
Setiap pilihan akan mengarahkan pengguna ke proses yang berbeda.
Misalnya, ketika pengguna memilih menu nomor 1, program meminta nama dan nilai murid. Jika memilih nomor 3, program menghitung statistik dari data yang sudah tersimpan.
Alur tersebut dapat diterjemahkan menjadi struktur percabangan dan perulangan dalam C++.
4. Menentukan Data yang Dibutuhkan
Selanjutnya, kita perlu menentukan jenis informasi yang akan disimpan oleh program.
Dalam proyek ini, setiap murid memiliki setidaknya dua informasi utama, yaitu nama dan nilai.
Nama merupakan teks, sedangkan nilai merupakan bilangan. Oleh karena itu, kita perlu menentukan tipe data yang sesuai.
| Informasi | Tipe Data | Contoh |
|---|---|---|
| Nama murid | string | "Andi Pratama" |
| Nilai murid | double | 85.5 |
Jika hanya menyimpan satu data, kita dapat menggunakan variabel biasa. Namun, program ini perlu menyimpan banyak murid. Karena itu, kita membutuhkan struktur data yang dapat mengelola sekumpulan informasi.
Menggunakan struct untuk mengelompokkan data
Dalam C++, kita dapat menggunakan struct untuk mengelompokkan beberapa informasi yang saling berkaitan.
struct Murid {
string nama;
double nilai;
};
Dengan struktur tersebut, satu objek Murid dapat menyimpan nama dan nilai secara bersamaan.
Untuk menyimpan banyak murid, kita dapat menggunakan vector.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
struct Murid {
string nama;
double nilai;
};
int main() {
vector<Murid> daftarMurid;
return 0;
}
Sekarang kita memiliki tempat untuk menyimpan banyak objek Murid dalam satu kumpulan data.
5. Membagi Program Menjadi Beberapa Fungsi
Ketika program mulai memiliki banyak fitur, menulis seluruh instruksi di dalam fungsi main() akan membuat kode menjadi panjang dan sulit dipahami.
Bayangkan seluruh proses tambah data, pencarian, perhitungan statistik, dan penyimpanan file ditulis dalam satu bagian besar. Ketika terjadi kesalahan, kita harus memeriksa banyak kode untuk menemukan sumber masalahnya.
Untuk menghindari hal tersebut, kita dapat membagi program menjadi beberapa fungsi.
Fungsi dalam proyek pemrograman
Fungsi memungkinkan kita mengelompokkan instruksi berdasarkan tugas tertentu. Setiap fungsi dapat memiliki tanggung jawab yang lebih jelas sehingga program lebih mudah dibaca, diuji, dan dikembangkan.
Contoh pembagian fungsi dalam proyek kita:
| Nama Fungsi | Tugas |
|---|---|
tampilkanMenu() |
Menampilkan menu utama. |
tambahMurid() |
Memasukkan data murid. |
tampilkanMurid() |
Menampilkan seluruh data. |
hitungStatistik() |
Menghitung rata-rata, tertinggi, dan terendah. |
cariMurid() |
Mencari data berdasarkan nama. |
simpanData() |
Menyimpan data ke file. |
muatData() |
Membaca data dari file. |
Dengan pembagian tersebut, fungsi main() dapat berperan sebagai pengatur alur utama program, sedangkan pekerjaan khusus dilakukan oleh fungsi masing-masing.
int main() {
// Memuat data awal
// Menampilkan menu
// Memproses pilihan pengguna
// Menyimpan data ketika diperlukan
return 0;
}
Ini baru gambaran tanggung jawab fungsi utama. Implementasi lengkapnya akan kita susun pada bagian berikutnya.
6. Mulai Menulis Kode Program
Setelah masalah, fitur, alur, dan struktur data dirancang, sekarang kita dapat mulai menulis kode.
Dalam proyek ini, kita akan membangun program secara bertahap. Tidak perlu langsung menulis semua fitur sekaligus.
Tahap pertama: membuat kerangka program
Kita mulai dengan menyiapkan pustaka yang dibutuhkan dan membuat struktur data Murid.
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <limits>
#include <algorithm>
using namespace std;
struct Murid {
string nama;
double nilai;
};
int main() {
vector<Murid> daftarMurid;
cout << "Program Pengelolaan Nilai Murid";
return 0;
}
Beberapa pustaka yang digunakan memiliki fungsi berbeda:
(- ) <iostream> untuk input dan output melalui console.
(- ) <vector> untuk menyimpan kumpulan data secara dinamis.
(- ) <string> untuk mengelola teks.
(- ) <fstream> untuk membaca dan menulis file.
(- ) <limits> untuk membantu membersihkan input yang tidak valid.
(- ) <algorithm> untuk menggunakan algoritma seperti pengurutan.
Tahap kedua: membuat fitur tambah data
Fitur pertama yang kita buat adalah memasukkan data murid.
Pengguna akan memasukkan nama dan nilai. Data tersebut kemudian disimpan ke dalam vector.
void tambahMurid(vector<Murid>& daftar) {
Murid murid;
cout << "Masukkan nama: ";
getline(cin, murid.nama);
cout << "Masukkan nilai: ";
cin >> murid.nilai;
daftar.push_back(murid);
cout << "Data berhasil ditambahkan.\n";
}
Perhatikan bahwa parameter vector<Murid>& daftar menggunakan reference. Dengan demikian, fungsi dapat menambahkan data langsung ke vector yang digunakan oleh program utama.
Untuk versi proyek yang lebih kuat, input nilai juga perlu divalidasi agar pengguna tidak memasukkan teks atau angka di luar rentang nilai yang diperbolehkan. Validasi akan kita terapkan dalam implementasi akhir.
Tahap ketiga: menampilkan seluruh data
Setelah data berhasil dimasukkan, kita perlu menyediakan fitur untuk melihat seluruh data yang tersimpan.
void tampilkanMurid(const vector<Murid>& daftar) {
if (daftar.empty()) {
cout << "Belum ada data murid.\n";
return;
}
for (const Murid& murid : daftar) {
cout << "Nama: " << murid.nama << endl;
cout << "Nilai: " << murid.nilai << endl;
cout << "-------------------\n";
}
}
Fungsi tersebut menggunakan perulangan untuk membaca setiap elemen vector. Kata kunci const menunjukkan bahwa fungsi hanya membaca data dan tidak mengubah isinya.
Tahap keempat: menghitung statistik nilai
Berikutnya, kita membuat fitur untuk menghitung rata-rata, nilai tertinggi, dan nilai terendah.
void hitungStatistik(const vector<Murid>& daftar) {
if (daftar.empty()) {
cout << "Belum ada data.\n";
return;
}
double total = 0;
double tertinggi = daftar[0].nilai;
double terendah = daftar[0].nilai;
for (const Murid& murid : daftar) {
total += murid.nilai;
if (murid.nilai > tertinggi) {
tertinggi = murid.nilai;
}
if (murid.nilai < terendah) {
terendah = murid.nilai;
}
}
double rataRata = total / daftar.size();
cout << "Rata-rata: " << rataRata << endl;
cout << "Nilai tertinggi: " << tertinggi << endl;
cout << "Nilai terendah: " << terendah << endl;
}
Di sini kita menggunakan algoritma perulangan untuk memproses seluruh data. Setiap nilai dijumlahkan, kemudian dibandingkan dengan nilai tertinggi dan terendah sementara.
Tahap kelima: membuat fitur pencarian
Program juga perlu membantu pengguna menemukan data berdasarkan nama murid.
void cariMurid(const vector<Murid>& daftar) {
string namaDicari;
cout << "Masukkan nama yang dicari: ";
getline(cin, namaDicari);
bool ditemukan = false;
for (const Murid& murid : daftar) {
if (murid.nama == namaDicari) {
cout << "Nama: " << murid.nama << endl;
cout << "Nilai: " << murid.nilai << endl;
ditemukan = true;
break;
}
}
if (!ditemukan) {
cout << "Data tidak ditemukan.\n";
}
}
Pencarian pada contoh ini menggunakan Linear Search. Program memeriksa nama satu per satu hingga menemukan data yang sesuai.
Jika data semakin banyak, kita dapat mempertimbangkan struktur data atau algoritma pencarian yang lebih sesuai.
7. Menambahkan Fitur Penyimpanan Data
Sampai tahap ini, program sudah dapat menerima, menampilkan, menghitung, dan mencari data. Namun, masih ada satu masalah penting.
Bagaimana jika program ditutup?
Data yang tersimpan di dalam vector hanya berada di memori selama program berjalan. Ketika program selesai, data tersebut tidak otomatis tersimpan sebagai file permanen.
Oleh karena itu, kita perlu menambahkan mekanisme penyimpanan ke dalam file.
Menggunakan file untuk menyimpan data
Dengan pustaka <fstream>, program C++ dapat menulis data ke file dan membaca kembali data tersebut ketika program dijalankan.
Kita akan menggunakan file bernama data_murid.txt.
void simpanData(const vector<Murid>& daftar) {
ofstream file("data_murid.txt");
if (!file) {
cout << "Gagal membuka file.\n";
return;
}
for (const Murid& murid : daftar) {
file << murid.nama << endl;
file << murid.nilai << endl;
}
cout << "Data berhasil disimpan.\n";
}
Setiap murid disimpan dalam dua baris: baris pertama berisi nama dan baris kedua berisi nilai.
Ketika program dijalankan kembali, kita perlu membaca file tersebut untuk memulihkan data.
void muatData(vector<Murid>& daftar) {
ifstream file("data_murid.txt");
if (!file) {
return;
}
Murid murid;
while (getline(file, murid.nama)) {
if (!(file >> murid.nilai)) {
break;
}
file.ignore(numeric_limits<streamsize>::max(), '\n');
daftar.push_back(murid);
}
cout << "Data berhasil dimuat.\n";
}
Dengan mekanisme tersebut, data dapat dibaca kembali ketika program dijalankan. Nama yang mengandung spasi juga dapat disimpan karena kita menggunakan getline().
Contoh ini menggunakan format teks sederhana. Untuk aplikasi yang lebih kompleks, format penyimpanan perlu dirancang lebih kuat agar dapat menangani data yang tidak lengkap, karakter khusus, dan perubahan struktur data.
8. Menggabungkan Seluruh Fitur Menjadi Program Utuh
Setelah setiap fitur dibuat, kita perlu menggabungkannya menjadi satu program yang dapat dijalankan dari awal hingga akhir.
Di sinilah fungsi main() berperan sebagai pengatur alur program.
Program akan memuat data dari file terlebih dahulu, kemudian menampilkan menu. Pengguna dapat memilih fitur yang ingin digunakan. Setelah memilih keluar, program menyimpan data dan mengakhiri proses.
Berikut implementasi lengkap proyek pengelolaan nilai murid.
Versi berikut menggabungkan fitur yang telah dirancang, sekaligus menambahkan validasi input angka dan rentang nilai 0–100. Data disimpan dalam format teks sederhana dengan pemisah baris.
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
#include <limits>
#include <algorithm>
#include <iomanip>
using namespace std;
struct Murid {
string nama;
double nilai;
};
// Membaca input angka dengan validasi
double inputNilai() {
double nilai;
while (true) {
cout << "Masukkan nilai (0-100): ";
if (cin >> nilai && nilai >= 0 && nilai <= 100) {
cin.ignore(
numeric_limits<streamsize>::max(),
'\n'
);
return nilai;
}
cout << "Input tidak valid.\n";
cin.clear();
cin.ignore(
numeric_limits<streamsize>::max(),
'\n'
);
}
}
// Menambahkan data murid
void tambahMurid(vector<Murid>& daftar) {
Murid murid;
cout << "Masukkan nama murid: ";
getline(cin, murid.nama);
if (murid.nama.empty()) {
cout << "Nama tidak boleh kosong.\n";
return;
}
murid.nilai = inputNilai();
daftar.push_back(murid);
cout << "Data berhasil ditambahkan.\n";
}
// Menampilkan seluruh data
void tampilkanMurid(const vector<Murid>& daftar) {
if (daftar.empty()) {
cout << "Belum ada data murid.\n";
return;
}
cout << "\nDAFTAR NILAI MURID\n";
cout << "------------------------------\n";
for (size_t i = 0; i < daftar.size(); i++) {
cout << i + 1 << ". "
<< daftar[i].nama
<< " - "
<< daftar[i].nilai
<< endl;
}
}
// Menghitung statistik
void hitungStatistik(const vector<Murid>& daftar) {
if (daftar.empty()) {
cout << "Belum ada data.\n";
return;
}
double total = 0;
double tertinggi = daftar[0].nilai;
double terendah = daftar[0].nilai;
for (const Murid& murid : daftar) {
total += murid.nilai;
tertinggi = max(tertinggi, murid.nilai);
terendah = min(terendah, murid.nilai);
}
double rataRata = total / daftar.size();
cout << fixed << setprecision(2);
cout << "\nSTATISTIK NILAI\n";
cout << "Rata-rata : " << rataRata << endl;
cout << "Nilai tertinggi : " << tertinggi << endl;
cout << "Nilai terendah : " << terendah << endl;
}
// Mencari data murid
void cariMurid(const vector<Murid>& daftar) {
string namaDicari;
cout << "Masukkan nama yang dicari: ";
getline(cin, namaDicari);
bool ditemukan = false;
for (const Murid& murid : daftar) {
if (murid.nama == namaDicari) {
cout << "Nama : " << murid.nama << endl;
cout << "Nilai : " << murid.nilai << endl;
ditemukan = true;
}
}
if (!ditemukan) {
cout << "Data tidak ditemukan.\n";
}
}
// Menyimpan data
bool simpanData(const vector<Murid>& daftar) {
ofstream file("data_murid.txt");
if (!file) {
cout << "Gagal membuka file untuk menyimpan.\n";
return false;
}
for (const Murid& murid : daftar) {
file << murid.nama << '\n';
file << murid.nilai << '\n';
}
if (!file) {
cout << "Terjadi kesalahan saat menulis file.\n";
return false;
}
return true;
}
// Memuat data
void muatData(vector<Murid>& daftar) {
ifstream file("data_murid.txt");
if (!file) {
cout << "Belum ada file data. Mulai dengan data kosong.\n";
return;
}
vector<Murid> dataSementara;
Murid murid;
while (getline(file, murid.nama)) {
if (!(file >> murid.nilai)) {
cout << "Format data tidak lengkap.\n";
break;
}
file.ignore(
numeric_limits<streamsize>::max(),
'\n'
);
if (murid.nama.empty() ||
murid.nilai < 0 ||
murid.nilai > 100) {
cout << "Data tidak valid ditemukan.\n";
break;
}
dataSementara.push_back(murid);
}
if (file.bad()) {
cout << "Terjadi kesalahan saat membaca file.\n";
return;
}
daftar = dataSementara;
cout << "Data berhasil dimuat: "
<< daftar.size()
<< " murid.\n";
}
// Menampilkan menu
void tampilkanMenu() {
cout << "\n================================\n";
cout << " PROGRAM PENGELOLAAN NILAI\n";
cout << "================================\n";
cout << "1. Tambah Data Murid\n";
cout << "2. Tampilkan Semua Data\n";
cout << "3. Hitung Statistik Nilai\n";
cout << "4. Cari Data Murid\n";
cout << "5. Simpan Data\n";
cout << "6. Keluar\n";
cout << "================================\n";
cout << "Pilih menu: ";
}
int main() {
vector<Murid> daftarMurid;
muatData(daftarMurid);
int pilihan;
do {
tampilkanMenu();
if (!(cin >> pilihan)) {
cout << "Pilihan harus berupa angka.\n";
cin.clear();
cin.ignore(
numeric_limits<streamsize>::max(),
'\n'
);
continue;
}
cin.ignore(
numeric_limits<streamsize>::max(),
'\n'
);
switch (pilihan) {
case 1:
tambahMurid(daftarMurid);
break;
case 2:
tampilkanMurid(daftarMurid);
break;
case 3:
hitungStatistik(daftarMurid);
break;
case 4:
cariMurid(daftarMurid);
break;
case 5:
if (simpanData(daftarMurid)) {
cout << "Data berhasil disimpan.\n";
}
break;
case 6:
if (simpanData(daftarMurid)) {
cout << "Data tersimpan. Program selesai.\n";
}
break;
default:
cout << "Pilihan tidak tersedia.\n";
}
} while (pilihan != 6);
return 0;
}
Program di atas sudah menggabungkan beberapa konsep C++ yang telah dipelajari sebelumnya. Pengguna dapat menambahkan data, menampilkan daftar nilai, menghitung statistik, mencari nama, menyimpan data, dan memuat kembali data dari file.
Perhatikan juga bahwa program tidak hanya berisi fungsi utama. Setiap fitur memiliki fungsi tersendiri sehingga kode lebih mudah dipahami dan dikelola.
Bagaimana menjalankan proyek ini?
1. Salin kode program ke editor C++.
2. Simpan dengan nama file, misalnya pengelolaan_nilai.cpp.
3. Kompilasi menggunakan compiler C++ yang mendukung standar C++11 atau lebih baru.
4. Jalankan program.
5. Tambahkan beberapa data murid, lalu coba seluruh menu.
6. Tutup program dan jalankan kembali. Periksa apakah data sebelumnya berhasil dimuat.
File data_murid.txt akan dibuat di direktori kerja program. Lokasi tersebut bergantung pada cara program dijalankan dan pengaturan IDE.
9. Menguji Program: Apakah Semua Fitur Berjalan?
Program yang berhasil dikompilasi belum tentu sudah benar.
Compiler hanya memastikan bahwa kode memenuhi aturan sintaks dan proses kompilasi. Program tetap perlu diuji untuk mengetahui apakah hasilnya sesuai dengan tujuan yang sudah ditentukan.
Misalnya, program berhasil dijalankan. Namun, apakah data benar-benar tersimpan? Apakah perhitungan rata-rata sudah tepat? Apakah pencarian nama bekerja? Bagaimana jika pengguna memasukkan input yang salah?
Semua pertanyaan tersebut perlu diperiksa melalui pengujian.
Membuat skenario pengujian
| Pengujian | Input atau Kondisi | Hasil yang Diharapkan |
|---|---|---|
| Tambah data | Nama Andi, nilai 85. | Data berhasil ditambahkan. |
| Input nilai tidak valid | Nilai 150 atau teks. | Program meminta input ulang. |
| Menampilkan data | Terdapat tiga data murid. | Ketiga data ditampilkan. |
| Statistik | Nilai 80, 90, 70. | Rata-rata 80, tertinggi 90, terendah 70. |
| Pencarian | Mencari nama yang tersedia. | Data yang sesuai ditemukan. |
| Data kosong | Belum ada murid. | Program menampilkan informasi bahwa data kosong. |
| Penyimpanan | Memilih menu simpan. | Data tersimpan ke file. |
| Membaca file | Program dijalankan kembali. | Data sebelumnya dapat dimuat. |
Pengujian sebaiknya tidak hanya dilakukan menggunakan kondisi normal. Kita juga perlu mencoba kondisi yang tidak biasa, seperti data kosong, input salah, atau file yang tidak tersedia.
Jangan hanya menguji apakah program dapat berjalan. Ujilah apakah program memberikan hasil yang benar pada berbagai kondisi yang mungkin terjadi.
10. Memahami Debugging: Menemukan dan Memperbaiki Kesalahan
Ketika membuat program, kita hampir pasti akan menemukan kesalahan. Bahkan program yang terlihat sederhana dapat menghasilkan output yang tidak sesuai harapan.
Proses mencari penyebab kesalahan dan memperbaikinya disebut debugging.
Kesalahan dalam program dapat muncul dalam beberapa bentuk.
A. Syntax Error
Kesalahan yang terjadi karena penulisan kode tidak mengikuti aturan bahasa pemrograman.
Contohnya, lupa menambahkan titik koma, salah menulis nama fungsi, atau menggunakan tanda kurung yang tidak lengkap.
B. Runtime Error
Kesalahan yang terjadi ketika program sedang dijalankan.
Contohnya, mengakses elemen di luar batas array, membagi dengan nol pada operasi tertentu, atau mengalami masalah ketika membaca file.
C. Logic Error
Kesalahan pada logika program. Kode mungkin berhasil dikompilasi dan dijalankan, tetapi hasilnya tidak sesuai dengan yang seharusnya.
Contohnya, menghitung rata-rata dengan membagi jumlah nilai menggunakan angka yang salah.
Contoh menemukan logic error
Misalnya, kita ingin menghitung rata-rata tiga nilai. Namun, program menggunakan rumus berikut:
double rataRata = (80 + 90 + 70) / 2;
Hasilnya adalah 120, padahal rata-rata yang benar adalah 80.
Kesalahannya bukan pada sintaks, melainkan pada logika perhitungan. Kita seharusnya membagi jumlah nilai dengan banyaknya data, yaitu tiga.
double rataRata = (80 + 90 + 70) / 3.0;
Melalui debugging, kita belajar bahwa menemukan kesalahan bukan sekadar memperbaiki kode yang ditandai compiler. Kita juga perlu memeriksa apakah proses dan hasil program sudah sesuai dengan tujuan awal.
11. Membuat Program Lebih Mudah Dikembangkan
Setelah seluruh fitur utama berjalan, pekerjaan kita belum tentu selesai. Sebuah proyek pemrograman dapat terus dikembangkan untuk memenuhi kebutuhan baru.
Misalnya, program pengelolaan nilai yang sudah dibuat masih memiliki beberapa keterbatasan:
(- ) Belum memiliki fitur mengubah nilai yang sudah dimasukkan.
(- ) Belum memiliki fitur menghapus data murid.
(- ) Belum dapat mengelompokkan murid berdasarkan kelas.
(- ) Belum memiliki tampilan grafik statistik.
(- ) Belum memiliki sistem akun pengguna.
Fitur-fitur tersebut dapat ditambahkan secara bertahap. Namun, semakin besar proyek, semakin penting pula kualitas struktur kode.
Mengenal modularisasi
Modularisasi adalah pendekatan membagi program menjadi bagian-bagian yang lebih kecil berdasarkan tanggung jawabnya.
Misalnya, jika proyek berkembang, kita dapat memisahkan kode menjadi beberapa file:
Ilustrasi pemisahan tanggung jawab program
Dengan pendekatan ini, kode dapat lebih mudah dikelola. Ketika ingin memperbaiki fitur penyimpanan, kita tidak harus mengubah seluruh bagian program.
Mengenal pemrograman berorientasi objek
Ketika proyek semakin kompleks, kita juga dapat mempertimbangkan penggunaan Object-Oriented Programming (OOP).
Dalam OOP, program dirancang menggunakan objek yang memiliki data dan perilaku. Misalnya, objek Murid dapat memiliki atribut nama dan nilai, serta perilaku tertentu yang berkaitan dengan pengelolaan data murid.
Namun, tidak semua proyek harus menggunakan OOP. Pemilihan pendekatan pemrograman sebaiknya disesuaikan dengan ukuran dan kebutuhan proyek.
12. Tahapan Umum dalam Membangun Proyek Pemrograman
Dari contoh proyek yang telah kita kerjakan, kita dapat menyimpulkan bahwa membangun program bukan hanya aktivitas menulis kode. Ada beberapa tahapan yang saling berkaitan.
Tahapan tersebut bukan aturan yang harus selalu berjalan satu arah. Dalam praktiknya, pengembang sering kembali ke tahap sebelumnya ketika menemukan masalah atau mendapatkan kebutuhan baru.
13. Mengenal Pengembangan Proyek Secara Iteratif
Dalam proyek sederhana, kita mungkin dapat merancang seluruh fitur terlebih dahulu kemudian menulis kode sampai selesai. Namun, pada proyek yang lebih besar, pendekatan seperti itu tidak selalu efektif.
Pengembang perangkat lunak sering menggunakan pendekatan iteratif, yaitu membangun program secara bertahap melalui beberapa siklus pengembangan.
Contohnya, proyek pengelolaan nilai dapat dikembangkan menjadi beberapa versi.
Versi 1 — Program dasar
Program dapat menerima dan menampilkan data murid.
Input OutputVersi 2 — Pengolahan data
Program dapat menghitung rata-rata, nilai tertinggi, dan nilai terendah.
Perulangan AlgoritmaVersi 3 — Penyimpanan data
Program dapat menyimpan dan membaca data dari file.
File I/O PersistensiVersi 4 — Penyempurnaan
Program mendapatkan validasi input, pencarian, pengubahan data, dan penghapusan data.
Validasi DebuggingDengan pendekatan bertahap, kita dapat menguji setiap versi sebelum menambahkan fitur berikutnya. Jika ada kesalahan, ruang pencarian sumber masalah juga lebih terbatas.
Apakah proyek pemrograman harus langsung sempurna?
Tidak. Dalam pengembangan perangkat lunak, versi awal dapat disebut prototype atau MVP (Minimum Viable Product), tergantung tujuan pengembangannya.
Prototype digunakan untuk menunjukkan atau menguji gagasan. MVP merupakan versi awal dengan fitur inti yang cukup untuk memberikan manfaat dan memperoleh umpan balik pengguna.
Untuk latihan belajar, kita dapat memulai dari program sederhana yang sudah menyelesaikan satu masalah dengan benar, lalu mengembangkannya secara bertahap.
15. Tantangan Proyek Mandiri
Sekarang kamu sudah melihat bagaimana sebuah program dibangun dari awal hingga dapat digunakan. Sebagai latihan, cobalah membuat proyek lain secara mandiri.
Pilih salah satu proyek berikut dan terapkan tahapan pengembangan yang sudah dipelajari.
Proyek 1 — Program Pengelolaan Inventaris
Buat program untuk mencatat barang yang tersedia di sebuah ruangan atau toko.
Fitur yang dapat dibuat:
(- ) Menambahkan barang.
(- ) Menampilkan daftar barang.
(- ) Mengubah jumlah stok.
(- ) Mencari barang berdasarkan nama.
(- ) Menyimpan data ke file.
Proyek 2 — Program Pengelolaan Keuangan Sederhana
Buat program untuk mencatat pemasukan dan pengeluaran.
Fitur yang dapat dibuat:
(- ) Mencatat pemasukan.
(- ) Mencatat pengeluaran.
(- ) Menghitung saldo.
(- ) Menampilkan riwayat transaksi.
(- ) Menyimpan riwayat transaksi ke file.
Proyek 3 — Program Perpustakaan Sederhana
Buat program untuk mengelola data buku dan peminjaman.
Fitur yang dapat dibuat:
(- ) Menambahkan data buku.
(- ) Menampilkan daftar buku.
(- ) Mencari buku.
(- ) Mencatat peminjaman dan pengembalian.
(- ) Menyimpan data buku ke file.
Untuk setiap proyek, jangan langsung mulai dengan menulis kode. Buat terlebih dahulu daftar masalah, tujuan, fitur, alur program, dan struktur data yang dibutuhkan.
Setelah itu, kembangkan program secara bertahap. Pastikan setiap fitur dapat berjalan sebelum melanjutkan ke fitur berikutnya.
16. Kesimpulan: Belajar Pemrograman dengan Membangun Sesuatu
Belajar pemrograman tidak berhenti ketika kita sudah memahami sintaks bahasa pemrograman. Kemampuan yang lebih penting adalah menggunakan berbagai konsep tersebut untuk menyelesaikan masalah nyata.
Melalui sebuah proyek, kita belajar menggabungkan variabel, tipe data, input-output, percabangan, perulangan, fungsi, struktur data, algoritma, dan pengolahan file menjadi satu program yang memiliki tujuan jelas.
Kita juga belajar bahwa proses pengembangan tidak selalu berjalan mulus. Ada kesalahan yang harus ditemukan, fitur yang perlu diperbaiki, dan kebutuhan yang mungkin berubah selama proyek berlangsung.
Hal utama yang perlu diingat
(- ) Mulailah dari masalah, bukan langsung dari kode.
(- ) Tentukan tujuan dan ruang lingkup proyek.
(- ) Rancang alur dan struktur data sebelum implementasi.
(- ) Bagi program menjadi fungsi-fungsi yang memiliki tanggung jawab jelas.
(- ) Bangun program secara bertahap.
(- ) Uji setiap fitur dan lakukan debugging.
(- ) Kembangkan program berdasarkan kebutuhan yang nyata.
Pada akhirnya, kemampuan membangun proyek merupakan salah satu tahap penting dalam perjalanan belajar pemrograman. Dari proyek sederhana, kita dapat memahami bagaimana konsep-konsep yang sebelumnya dipelajari secara terpisah ternyata saling terhubung untuk menghasilkan sebuah aplikasi.