Membangun dengan titik kontrol

Menjaga spec hijau pada setiap commit sebagai titik kontrol kemajuan.

Daftar isi

Alur kerja commit kecil menjadikan setiap commit sebagai titik kontrol kemajuan proyek, yaitu kondisi yang sudah teruji dan dapat dikembalikan kapan pun. Topik ini mempraktikkan alur tersebut pada proyek penghitung statistik bernama statistik-angka, mulai dari kerangka proyek hasil crystal init app, commit pertama yang dijaga oleh spec hijau, penambahan fitur kedua, sampai pembacaan buku besar commit melalui git log. Setiap commit hanya dibuat setelah pengujian lolos, sehingga daftar commit sekaligus menjadi daftar kondisi proyek yang diketahui berjalan dengan benar.

Kerangka proyek dan repositori git#

Kerangka proyek dibuat dengan crystal init app, dan perintah yang sama sekaligus menyiapkan repositori git yang akan mencatat titik-titik kontrolnya. Nama proyek menentukan nama folder, nama module di dalam kode, serta nama berkas sumbernya. Jalankan perintah berikut pada folder tempat proyek akan berdiri.

bash
# bersihkan sisa proyek lama bila ada, lalu buat kerangka proyek
rm -rf statistik-angka
crystal init app statistik-angka
text Keluaran
    create  /home/kal/my-project/content/crystal/pengerjaan-proyek/membangun-dengan-titik-kontrol/statistik-angka/.gitignore
    create  /home/kal/my-project/content/crystal/pengerjaan-proyek/membangun-dengan-titik-kontrol/statistik-angka/.editorconfig
    create  /home/kal/my-project/content/crystal/pengerjaan-proyek/membangun-dengan-titik-kontrol/statistik-angka/LICENSE
    create  /home/kal/my-project/content/crystal/pengerjaan-proyek/membangun-dengan-titik-kontrol/statistik-angka/README.md
    create  /home/kal/my-project/content/crystal/pengerjaan-proyek/membangun-dengan-titik-kontrol/statistik-angka/shard.yml
    create  /home/kal/my-project/content/crystal/pengerjaan-proyek/membangun-dengan-titik-kontrol/statistik-angka/src/statistik-angka.cr
    create  /home/kal/my-project/content/crystal/pengerjaan-proyek/membangun-dengan-titik-kontrol/statistik-angka/spec/spec_helper.cr
    create  /home/kal/my-project/content/crystal/pengerjaan-proyek/membangun-dengan-titik-kontrol/statistik-angka/spec/statistik-angka_spec.cr
Initialized empty Git repository in /home/kal/my-project/content/crystal/pengerjaan-proyek/membangun-dengan-titik-kontrol/statistik-angka/.git/

Baris create mencantumkan berkas kerangka yang dibuat, sedangkan baris terakhir berasal dari git yang menyiapkan repositori kosong di dalam folder proyek. Struktur yang terbentuk adalah sebagai berikut.

text Struktur proyek statistik-angka
statistik-angka/
├── .editorconfig
├── .gitignore
├── LICENSE
├── README.md
├── shard.yml
├── spec/
│   ├── spec_helper.cr
│   └── statistik-angka_spec.cr
└── src/
    └── statistik-angka.cr

Repositori git hasil init masih kosong, artinya belum ada satu commit pun yang tercatat. Seluruh berkas kerangka karenanya berstatus belum tercatat (untracked) sampai commit pertama dibuat pada bagian berikutnya. Folder src/ menampung kode sumber, folder spec/ menampung pengujian, dan shard.yml menjadi manifest proyek. Ketiga bagian itu akan ikut tercatat pada titik kontrol pertama.

Commit pertama dengan spec hijau#

Versi pertama modul menyediakan dua hitungan statistik, yaitu jumlah untuk menjumlahkan seluruh angka pada daftar dan rata_rata untuk membagi jumlah tersebut dengan banyak elemennya. Isi kedua berkasnya adalah sebagai berikut.

crystal src/statistik-angka.cr
module Statistik::Angka
  VERSION = "0.1.0"

  def self.jumlah(angka : Array(Float64)) : Float64
    angka.sum
  end

  def self.rata_rata(angka : Array(Float64)) : Float64
    jumlah(angka) / angka.size
  end
end
crystal spec/statistik-angka_spec.cr
require "./spec_helper"

describe Statistik::Angka do
  describe ".jumlah" do
    it "menjumlahkan seluruh angka pada daftar" do
      Statistik::Angka.jumlah([80.0, 90.0, 100.0]).should eq(270.0)
    end
  end

  describe ".rata_rata" do
    it "menghitung rata-rata daftar nilai ujian" do
      Statistik::Angka.rata_rata([80.0, 90.0, 100.0]).should eq(90.0)
    end
  end
end

Metode jumlah mendelegasikan pekerjaannya kepada Array#sum, sedangkan rata_rata memanggil jumlah lalu membagi hasilnya dengan angka.size. Spec menguji keduanya dengan daftar nilai ujian [80.0, 90.0, 100.0] yang hasilnya mudah diperiksa, yaitu 270.0 untuk jumlah dan 90.0 untuk rata-rata. Berkas contoh di samping proyek disalin ke tempat semestinya, kemudian spec dijalankan lebih dahulu sebelum commit dicatat.

bash
# masuk ke folder proyek
cd statistik-angka

# salin berkas contoh di samping proyek ke tempat semestinya
cp ../src/statistik-angka.cr src/statistik-angka.cr
cp ../spec/statistik-angka_spec.cr spec/statistik-angka_spec.cr

# jalankan pengujian
# baris "Finished in" disaring karena waktunya selalu berubah
crystal spec 2>&1 | grep -v "^Finished in"
text Keluaran
..

2 examples, 0 failures, 0 errors, 0 pending

Setiap titik pada baris pertama melambangkan satu contoh yang lolos, dan ringkasan di bawahnya mengonfirmasi dua contoh tanpa kegagalan. Kondisi inilah yang disebut spec hijau, yaitu seluruh pengujian lolos pada kode yang sedang dikerjakan. Spec yang hijau merupakan syarat masuk bagi sebuah titik kontrol, sehingga commit baru dibuat setelah keadaan ini tercapai.

Commit pertama dicatat dengan tiga langkah git. git status --short digunakan untuk melihat kondisi berkas, git add -A menandai seluruhnya, dan git commit merekamnya. Identitas penulis diisi melalui opsi -c agar setiap commit pada topik ini menggunakan nama dan surel yang sama tanpa bergantung pada pengaturan git global, sedangkan opsi -q menekan keluaran commit yang memuat kode (hash) yang panjangnya berubah-ubah.

bash
# lihat kondisi berkas menurut git
git status --short

# catat seluruh berkas sebagai commit pertama
git add -A
git -c user.name="Ali" -c user.email="[email protected]" commit -q -m "Tambah hitungan jumlah dan rata-rata"

# tampilkan daftar subjek commit
git log --format="%s"
text Keluaran
?? .editorconfig
?? .gitignore
?? LICENSE
?? README.md
?? shard.yml
?? spec/
?? src/
Tambah hitungan jumlah dan rata-rata

Kode ?? pada daftar status menandai berkas dan folder yang belum pernah tercatat git, yang cocok dengan repositori yang masih kosong. Setelah git add -A dan commit dijalankan, git log --format="%s" menampilkan subjek commit pertama. Format %s dipilih karena hanya mencetak subjeknya, sehingga daftar tersebut terbaca seperti judul bab dan bukan deretan kode hash yang sulit dibandingkan.

Menambah fitur pada titik kontrol berikutnya#

Fitur kedua menambahkan dua metode ekstrem, yaitu terbesar yang mengembalikan nilai tertinggi dan terkecil yang mengembalikan nilai terendah. Keduanya ditambahkan melalui cat >> yang menyambung teks baru pada akhir berkas tanpa menghapus isinya. Module pada Crystal boleh dibuka kembali, artinya deklarasi module Statistik::Angka yang kedua tidak membuat module baru, melainkan menambahkan metode ke module yang sama.

bash
# tambahkan method terbesar dan terkecil pada berkas sumber
cat >> src/statistik-angka.cr <<'EOF'

module Statistik::Angka
  def self.terbesar(angka : Array(Float64)) : Float64
    angka.max
  end

  def self.terkecil(angka : Array(Float64)) : Float64
    angka.min
  end
end
EOF

# tambahkan dua contoh pengujian pada spec
cat >> spec/statistik-angka_spec.cr <<'EOF'

describe Statistik::Angka do
  describe ".terbesar" do
    it "menemukan nilai tertinggi pada daftar" do
      Statistik::Angka.terbesar([12.0, 7.0, 30.0]).should eq(30.0)
    end
  end

  describe ".terkecil" do
    it "menemukan nilai terendah pada daftar" do
      Statistik::Angka.terkecil([12.0, 7.0, 30.0]).should eq(7.0)
    end
  end
end
EOF

# jalankan ulang seluruh spec
# baris "Finished in" disaring karena waktunya selalu berubah
crystal spec 2>&1 | grep -v "^Finished in"
text Keluaran
....

4 examples, 0 failures, 0 errors, 0 pending

Empat titik pada keluaran menandakan empat contoh lolos, dua dari commit pertama dan dua dari fitur baru. Contoh lama tetap dijalankan setiap saat, sehingga fitur baru yang merusak perilaku lama akan langsung memerah pada laporan. Spec kembali hijau, dan kondisi ini siap dicatat sebagai titik kontrol kedua.

bash
# periksa berkas yang berubah sejak commit terakhir
git status --short

# catat fitur kedua sebagai commit baru
git add -A
git -c user.name="Ali" -c user.email="[email protected]" commit -q -m "Tambah hitungan terbesar dan terkecil"

# buku besar kemajuan berupa daftar subjek commit
git log --format="%s"

# jumlah commit yang sudah tercatat
git log --oneline | wc -l
text Keluaran
 M spec/statistik-angka_spec.cr
 M src/statistik-angka.cr
Tambah hitungan terbesar dan terkecil
Tambah hitungan jumlah dan rata-rata
2

Kode M kali ini menandai berkas yang berubah sejak commit terakhir, dan urutannya mengikuti abjad nama berkas. Daftar subjek commit kini memuat dua baris yang masing-masing mewakili satu fitur yang sudah teruji, sementara git log --oneline | wc -l mengonfirmasi jumlahnya dua. Buku besar semacam ini membuat kemajuan proyek dapat dibaca dari luar, dan setiap barisnya dapat dikembalikan atau diperiksa ulang secara terpisah.

Kesalahan umum#

  • Satu commit memuat beberapa fitur sekaligus. Titik kontrol semacam ini sulit dikembalikan sebagian karena perubahannya menumpuk pada satu rekaman. Pecahkan pekerjaan per fitur, dan buat satu commit untuk satu fitur yang lolos spec.
  • Commit dijalankan tanpa git add terlebih dahulu, sehingga git menolak dengan pesan “nothing to commit” karena tidak ada perubahan yang ditandai. Periksa git status --short sebelum dan sesudah commit untuk memastikan perubahan benar-benar tercatat.
  • Subjek commit menjelaskan isi berkas alih-alih perubahannya, misalnya “statistik-angka.cr”. Subjek seperti itu tidak memberi informasi saat buku besar dibaca kembali. Gunakan kalimat imperatif yang menyebut perubahannya, misalnya “Tambah hitungan terbesar dan terkecil”.
  • Jarak antarcommit terlalu jauh sehingga satu titik kontrol memuat perubahan yang banyak dan beragam. Semakin jarang commit dibuat, semakin sulit menemukan commit yang menyebabkan masalah apabila muncul. Buat commit setiap kali satu fitur selesai dan specnya hijau.

Ringkasan#

  • crystal init app membuat kerangka proyek sekaligus repositori git yang masih kosong, sehingga commit pertama sepenuhnya ditulis sendiri.
  • Titik kontrol mengikuti urutan tetap, yaitu crystal spec hijau terlebih dahulu, kemudian git add -A dan commit dengan subjek yang menjelaskan perubahannya.
  • Module pada Crystal boleh dibuka kembali, sehingga fitur baru dapat ditambahkan pada akhir berkas tanpa menyunting deklarasi yang lama.
  • git log --format="%s" menampilkan buku besar kemajuan berupa daftar subjek commit, satu baris untuk setiap kondisi proyek yang sudah teruji.

Referensi#