Pembangunan dengan titik pemeriksaan

Potongan vertikal di atas infrastruktur nyata.

Daftar isi

Arsitektur yang sudah ditetapkan berperan sebagai cetak biru, sedangkan pengerjaannya membutuhkan metode agar kemajuannya selalu dapat diukur. Topik ini menerapkan metode potongan vertikal (vertical slice), yaitu membangun perilaku utuh yang melintasi semua lapisan dalam langkah kecil bernama titik pemeriksaan. Setiap titik menghasilkan perilaku yang dapat didemokan, sehingga kemajuan proyek diukur dari demo yang berjalan, bukan dari jumlah berkas yang sudah ditulis.

Potongan vertikal sebagai satuan kemajuan#

Potongan vertikal berlawanan arah dengan pembangunan per lapisan. Cara per lapisan menuntaskan satu lapisan untuk semua fitur, misalnya seluruh skema database dibuat lebih dahulu, kemudian seluruh context, lalu seluruh halaman. Sistemnya baru bergerak pada tahap terakhir, sehingga kesalahan desain pada lapisan awal baru terlihat setelah banyak kode ditumpuk di atasnya. Potongan vertikal memilih arah sebaliknya, yaitu satu perilaku diselesaikan dari ujung ke ujung dalam ukuran yang kecil. Perilaku “kartu dapat dibuat lalu tersimpan” melintasi Repo, context, dan halaman sekaligus, tetapi hanya untuk satu perilaku.

Satuan kecil ini memberi tiga keuntungan yang menyertai setiap langkah. Infrastruktur nyata dipasang sejak potongan pertama, sehingga integrasi antar lapisan diuji terus-menerus dan tidak tertunda sampai akhir proyek. Feedback berupa demo yang berjalan hadir setiap beberapa hari kerja. Regresi juga terlihat cepat, karena perilaku yang sudah lulus satu titik dapat diuji ulang kapan saja dengan biaya yang hampir nol.

Lima titik pemeriksaan#

Titik pemeriksaan disusun dari kerangka kosong sampai sistem produksi, dan nomornya menunjukkan urutan yang disarankan. Setiap titik hanya boleh dinyatakan selesai apabila bukti demonya tampil, bukan apabila kodenya tampak lengkap:

TitikPerilaku yang didemokanInfrastruktur yang disentuh
P0halaman sambutan tampil di localhost:4000proyek Phoenix, endpoint
P1kartu dapat dibuat, dibaca, dan tersimpanRepo, Ecto, context, LiveView
P2perubahan pada satu halaman terlihat di halaman lain tanpa muat ulangPubSub broadcast
P3daftar pengguna daring tampil dan berubah secara langsungpresence
P4sistem berjalan dari artefak rilis di luar folder proyekmix release

Daftar periksa berikut menyajikan isi tabel di atas dalam bentuk yang dapat direproduksi. Tandai satu titik selesai hanya apabila buktinya terlihat di layar:

  • P0: perintah mix phx.server berjalan dan halaman sambutan terbuka di browser.
  • P1: kartu baru dibuat melalui halaman, lalu masih ada setelah server dihidupkan ulang.
  • P2: dua halaman dibuka berdampingan, perpindahan kartu di satu halaman langsung tampil di halaman lainnya.
  • P3: daftar daring bertambah ketika halaman baru dibuka dan berkurang ketika halamannya ditutup.
  • P4: artefak rilis dijalankan dengan variabel lingkungan produksi dan halamannya terbuka.

Simulasi titik pemeriksaan P2#

Titik P2 berdiri di atas PubSub, dan mekanismenya dapat dibuktikan lebih dahulu sebelum halamannya dibangun. Skrip berikut memulai PubSub asli, menghadirkan dua pelanggan pada topik yang sama, lalu mengirim satu broadcast. Pelanggan pertama berupa process lain yang menyimulasikan satu LiveView yang sedang terbuka, sedangkan pelanggan kedua berupa process utama skrip. Kerja sama keduanya dijaga dengan pesan {:siap, ...} yang memastikan broadcast baru dikirim setelah kedua pelanggan selesai berlangganan:

elixir titik_p2.exs
# titik_p2.exs — simulasi titik pemeriksaan P2: satu broadcast, dua pelanggan
Mix.install([{:phoenix, "~> 1.8"}, {:jason, "~> 1.4"}])
Logger.configure(level: :warning)

# PubSub dimulai sebagai anak supervisor, persis seperti dalam proyek Phoenix
{:ok, _} = Supervisor.start_link([{Phoenix.PubSub, name: :papan_pubsub}], strategy: :one_for_one)

induk = self()

# pelanggan pertama: process lain, menyimulasikan satu LiveView yang sedang terbuka
spawn(fn ->
  Phoenix.PubSub.subscribe(:papan_pubsub, "papan:tugas")
  send(induk, {:siap, :liveview})

  receive do
    {:geser, kartu, kolom} -> send(induk, {:terima, :liveview, {kartu, kolom}})
  after
    3000 -> send(induk, {:gagal, :liveview})
  end
end)

# pelanggan kedua: process utama skrip, menyimulasikan pelanggan lain
Phoenix.PubSub.subscribe(:papan_pubsub, "papan:tugas")

receive do
  {:siap, _siapa} -> :ok
after
  3000 -> exit(:pelanggan_tidak_siap)
end

Phoenix.PubSub.broadcast(:papan_pubsub, "papan:tugas", {:geser, "kartu-1", "selesai"})

utama =
  receive do
    {:geser, kartu, kolom} -> {kartu, kolom}
  after
    3000 -> :waktu_habis
  end

IO.inspect(utama, label: "pelanggan utama menerima")

lain =
  receive do
    {:terima, siapa, isi} -> {siapa, isi}
    {:gagal, siapa} -> {:gagal, siapa}
  after
    3000 -> :waktu_habis
  end

IO.inspect(lain, label: "pelanggan kedua menerima")
text Keluaran
pelanggan utama menerima: {"kartu-1", "selesai"}
pelanggan kedua menerima: {:liveview, {"kartu-1", "selesai"}}

Keluaran memperlihatkan bahwa satu broadcast sampai ke dua process yang berbeda. Pelanggan utama menerima pesan geser kartu secara langsung, sedangkan pelanggan yang menyimulasikan LiveView meneruskannya dengan pesan {:terima, ...} beserta penandanya. Jalur gagal pada skrip tetap terjaga, karena setiap receive diakhiri timeout, sehingga pelanggan yang belum berlangganan melaporkan {:gagal, ...} alih-alih membuat skrip diam selamanya. Mekanisme inilah yang nantinya diuji ulang pada demo P2, dengan dua halaman sungguhan menggantikan kedua process pelanggan.

Kesalahan umum#

Kesalahan pertama adalah menumpuk beberapa titik dalam satu potongan, misalnya membangun CRUD, broadcast, dan presence sekaligus. Ketika halaman tidak bergerak, sumber masalahnya dapat berada di tiga lapisan berbeda, dan waktu pencariannya jauh lebih lama daripada waktu yang dihemat. Satu titik pemeriksaan berarti satu perilaku baru yang didemokan sebelum titik berikutnya dimulai.

Kesalahan kedua adalah memeriksa dengan membaca kode alih-alih mendemokannya. Kode yang tampak lengkap belum membuktikan apa pun, sedangkan demo memaksa seluruh lapisan bekerja bersama pada saat yang sama. Bukti keberhasilan setiap titik pada daftar periksa sengaja ditulis sebagai kejadian yang terlihat di layar.

Kesalahan ketiga adalah melanjutkan ke titik berikut dengan titik lama yang sudah rusak. Perilaku baru yang dibangun di atas demo yang gagal menumpuk kerusakan pada beberapa lapisan sekaligus. Jalankan ulang seluruh daftar periksa setiap kali perilaku baru ditambahkan, dan mundur ke commit titik terakhir yang berfungsi apabila ada yang berubah.

Ringkasan#

  • Potongan vertikal menyelesaikan satu perilaku dari ujung ke ujung, sehingga infrastruktur nyata terpasang sejak potongan pertama dan regresi terlihat cepat.
  • Lima titik pemeriksaan bergerak dari kerangka Phoenix, CRUD, PubSub, presence, sampai artefak rilis, dan setiap titik selesai hanya apabila demonya tampil.
  • Mekanisme titik P2 berupa satu broadcast PubSub yang sampai ke semua pelanggan topik, lengkap dengan timeout agar kegagalannya terlihat.
  • Daftar periksa diuji ulang setiap penambahan perilaku, dan commit per titik menyediakan jalan mundur yang selalu berfungsi.

Referensi#