Membangun dengan titik pemeriksaan

Menjaga proyek tetap berjalan dan diuji pada setiap tahap melalui titik pemeriksaan build dan silang.

Daftar isi

Proyek gagal jarang karena satu error besar, melainkan karena perbaikan menumpuk di atas fondasi yang belum pernah diverifikasi. Titik pemeriksaan (checkpoint) memecahnya, yaitu sekumpulan verifikasi singkat yang dijalankan berulang pada setiap tahap dan wajib lulus sebelum pekerjaan berlanjut. Untuk proyek Zig, tiga titiknya baku, yaitu pemeriksaan unit, build dan eksekusi lokal, serta kompilasi silang ke target tujuan. Topik ini membangun proyek kecil dengan graf build yang memuat ketiganya.

Ketiga titik itu dapat ditambah satu verifikasi keempat tanpa alat baru, yaitu menjalankan build dengan mode rilis melalui -Doptimize=ReleaseSafe. Mode ini mempertahankan pemeriksaan keamanan runtime seperti luapan integer dan pelanggaran batas slice, tetapi mengaktifkan optimasi, sehingga kelas error yang baru muncul saat optimasi tertangkap sejak dini. Titik-titik pemeriksaan pada proyek nyata biasanya dijalankan otomatis oleh layanan integrasi berkelanjutan setiap kali kode dikirim ke repositori, dan perintahnya persis sama dengan yang diketik manual di sini.

Konsep#

Titik pertama adalah zig test atas modul inti, yang memverifikasi logika tanpa menyentuh lapisan CLI. Titik kedua adalah zig build beserta eksekusi hasilnya, yang memverifikasi bahwa program utuh tersambung dan berjalan. Titik ketiga adalah zig build -Dtarget=<triple>, yang memverifikasi portabilitas dengan membangun untuk target tujuan sejak dini, bukan menjelang akhir.

Ketiganya dinyatakan sekali pada build.zig, sehingga menjalankannya kembali hanya memerlukan satu perintah per titik. Proyek dengan test step pada graf build menempatkan zig build test sebagai pintu masuk titik pertama, dan inilah bentuk yang dipakai proyek nyata sebagaimana diajarkan pada modul Pengujian. Urutan kerjanya berulang per tahap, yaitu menulis satu potongan kecil, menjalankan ketiga titik, lalu melanjutkan hanya bila semuanya lulus.

Diagram berikut memperlihatkan perulangan tersebut beserta perintahnya.

tulis potongan kecilzig testlogika intizig build runutuh lokalzig -Dtargetportabilitasketiganya lulus?yabelumlanjut tahap berikutperbaiki di tempatulangi ketiga titik
Perulangan kerja proyek dengan tiga titik pemeriksaan yang wajib lulus sebelum lanjut

Contoh Lengkap#

Proyek contohnya bernama pengukur, berisi modul konversi suhu dengan dua pemeriksaan, program CLI yang memakainya, dan graf build yang menyambungkan keduanya beserta test step-nya.

zig konversi.zig
// tidak-dijalankan: berkas modul diuji lewat perintah zig test dan zig build test
const std = @import("std");

pub fn celsius_ke_fahrenheit(celsius: f64) f64 {
    return celsius * 1.8 + 32.0;
}

pub fn fahrenheit_ke_celsius(fahrenheit: f64) f64 {
    return (fahrenheit - 32.0) / 1.8;
}

test "titik didih air sesuai definisi" {
    try std.testing.expectApproxEqAbs(@as(f64, 212.0), celsius_ke_fahrenheit(100.0), 0.001);
    try std.testing.expectApproxEqAbs(@as(f64, 100.0), fahrenheit_ke_celsius(212.0), 0.001);
}

test "titik beku air sesuai definisi" {
    try std.testing.expectApproxEqAbs(@as(f64, 32.0), celsius_ke_fahrenheit(0.0), 0.001);
}

Modul ini adalah inti yang dapat diuji, dan kedua pemeriksaannya memakai nilai definisi skala suhu sebagai kebenarannya. Program utamanya tipis, yaitu mencetak tabel konversi dari modul.

zig utama.zig
// tidak-dijalankan: berkas program dieksekusi lewat graf build pada build.zig
const std = @import("std");
const konversi = @import("konversi");

pub fn main() void {
    const celsius = [_]f64{ 0, 36.6, 100 };
    for (celsius) |c| {
        std.debug.print("{d:>5.1} C = {d:>5.1} F\n", .{ c, konversi.celsius_ke_fahrenheit(c) });
    }
}

Graf build menyatakan modul konversi, executable pengukur yang meng-import-nya, dan test step yang menjalankan pemeriksaan modul.

zig build.zig
// tidak-dijalankan: berkas build dieksekusi lewat perintah zig build
const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const mod = b.addModule("konversi", .{
        .root_source_file = b.path("konversi.zig"),
        .target = target,
        .optimize = optimize,
    });

    const exe = b.addExecutable(.{
        .name = "pengukur",
        .root_module = b.createModule(.{
            .root_source_file = b.path("utama.zig"),
            .target = target,
            .optimize = optimize,
            .imports = &.{
                .{ .name = "konversi", .module = mod },
            },
        }),
    });
    b.installArtifact(exe);

    const mod_tests = b.addTest(.{ .root_module = mod });
    const run_mod_tests = b.addRunArtifact(mod_tests);
    const test_step = b.step("test", "Jalankan pemeriksaan");
    test_step.dependOn(&run_mod_tests.step);
}

Titik pemeriksaan pertama dijalankan pada modul inti.

bash
zig test konversi.zig
text Keluaran
1/2 konversi.test.titik didih air sesuai definisi...OK
2/2 konversi.test.titik beku air sesuai definisi...OK
All 2 tests passed.

Titik kedua membangun dan mengeksekusi program utuh.

bash
zig build
./zig-out/bin/pengukur
text Keluaran
  0.0 C =  32.0 F
 36.6 C =  97.9 F
100.0 C = 212.0 F

Titik ketiga memverifikasi portabilitas ke target ARM64 Linux, dan identitas binernya diperiksa dengan file.

bash
zig build -Dtarget=aarch64-linux
file zig-out/bin/pengukur
text Keluaran
zig-out/bin/pengukur: ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked, with debug_info, not stripped

Ketiga keluaran berasal dari sumber yang sama pada keadaan yang sama, sehingga proyek terbukti benar secara logika, utuh secara build, dan portabel ke target tujuannya. Perulangan berikutnya, misalnya menambah fungsi kelvin pada modul, mengulangi ketiga perintah yang sama tanpa perubahan apa pun.

Ketiga titik ini juga menjadi kontrak bagi kerja sama tim. Teman satu proyek yang menarik perubahan hanya perlu menjalankan tiga perintah yang sama untuk menilai keadaan proyek, dan pesan laporan pemeriksaannya menunjuk langsung potongan yang gagal. Konsistensi perintah antar anggota tim karenanya ikut terjaga, karena tidak ada langkah verifikasi yang hanya diketahui satu orang.

Kesalahan umum#

Kesalahan kedua berupa memverifikasi hanya pada target lokal. Program yang lulus di mesin sendiri belum tentu lulus di target distribusi, karena perbedaan ABI dan lebar tipe berdampak nyata, dan kegagalan kompilasi silang yang ditemukan menjelang rilis menuntut penelusuran ulang yang besar. Titik ketiga berbiaya rendah dan dikerjakan sejak tahap pertama.

Kesalahan ketiga berupa menumpuk verifikasi pada satu langkah monolitik. Menjadikan satu perintah raksasa yang membangun, menguji, menjalankan, dan mengemas sekaligus membuat kegagalan sulit dilokalisasi dan memaksa seluruh langkah diulang. Titik pemeriksaan dipisah per perintah, dan build.zig menghubungkan, bukan menggabungkannya.

Ringkasan#

  • Tiga titik pemeriksaan baku berupa pemeriksaan unit, build dan eksekusi lokal, serta kompilasi silang ke target tujuan.
  • build.zig proyek menyatakan modul inti, executable, dan test step sehingga setiap titik berupa satu perintah.
  • Proyek contoh terbukti benar, utuh, dan portabel dari tiga keluaran yang dihasilkan sumber yang sama.
  • Perulangan kerjanya berupa potongan kecil, ketiga titik, lalu lanjut hanya bila semuanya lulus.

Dengan titik pemeriksaan ini, seluruh perangkat jalur Zig telah tersambung menjadi satu cara kerja proyek, dari modul inti yang teruji sampai biner silang yang siap dibagikan.

Referensi#