Mengapa saya menggunakan kontrak kode

26

Baru-baru ini saya menemukan kerangka kerja Microsoft untuk kontrak kode.

Saya membaca sedikit dokumentasi dan mendapati diri saya terus-menerus bertanya: "Mengapa saya ingin melakukan ini, karena tidak dan sering tidak dapat melakukan analisis statis."

Sekarang, saya sudah memiliki semacam gaya pemrograman defensif, dengan menjaga pengecualian seperti ini:

if(var == null) { throw new NullArgumentException(); }

Saya juga menggunakan banyak Pola NullObject dan jarang memiliki masalah. Tambahkan Tes Unit untuk itu dan Anda sudah siap.

Saya tidak pernah menggunakan pernyataan dan tidak pernah melewatkannya. Justru sebaliknya. Saya benar-benar benci kode yang memiliki banyak pernyataan tidak berarti di dalamnya, yang hanya mengganggu saya dan mengalihkan perhatian saya dari apa yang benar-benar ingin saya lihat. Kontrak kode, setidaknya cara Microsoft hampir sama - dan bahkan lebih buruk. Mereka menambahkan banyak kebisingan dan kerumitan pada kode. Dalam 99% pengecualian akan tetap terlempar - jadi saya tidak peduli apakah itu dari pernyataan / kontrak atau masalah aktual. Hanya sangat, sangat sedikit kasus tetap di mana program menyatakan benar-benar menjadi rusak.

Terus terang, apa manfaat menggunakan kontrak kode? Apakah ada? Jika Anda sudah menggunakan unit test dan kode secara defensif saya merasa bahwa memperkenalkan kontrak tidak sepadan dengan biayanya dan membuat kebisingan dalam kode Anda bahwa seorang pengelola akan mengutuk ketika dia memperbarui metode itu, sama seperti yang saya lakukan ketika saya tidak dapat melihat apa yang dilakukan kode tersebut. karena pernyataan tidak berguna. Saya belum melihat alasan bagus untuk membayar harga itu.

Elang
sumber
1
Mengapa Anda mengatakan "tidak dan sering tidak dapat melakukan analisis statis"? Saya pikir itu adalah salah satu poin dari proyek ini (bukan hanya menggunakan Asserts atau melemparkan pengecualian defensif)?
Carson63000
@ Carson63000 Baca dokumentasi dengan seksama dan Anda akan menemukan bahwa pemeriksa statis hanya akan mengeluarkan banyak dan banyak peringatan, yang paling tidak perlu, (para pengembang mengakuinya demikian) dan bahwa sebagian besar kontrak yang ditentukan hanya akan melemparkan pengecualian dan tidak melakukan apa pun selain .
Falcon
@ Falcon: anehnya, pengalaman saya benar-benar berbeda. Analisis statis berfungsi tidak sempurna, tetapi cukup baik, dan saya jarang melihat peringatan yang tidak perlu, bahkan ketika bekerja di tingkat peringatan 4 (tertinggi).
Arseni Mourzenko
Saya kira saya harus mencobanya untuk mengetahui bagaimana perilakunya.
Falcon

Jawaban:

42

Anda mungkin juga bertanya kapan pengetikan statis lebih baik daripada pengetikan dinamis. Debat yang telah berkecamuk selama bertahun-tahun tanpa akhir yang terlihat. Jadi lihatlah pertanyaan-pertanyaan seperti studi bahasa yang diketik secara dinamis vs. Statis

Tetapi argumen dasar akan menjadi potensi untuk menemukan dan memperbaiki masalah pada waktu kompilasi yang mungkin telah tergelincir ke dalam produksi.

Kontrak vs Pengawal

Bahkan dengan penjaga dan pengecualian Anda masih dihadapkan dengan masalah bahwa sistem akan gagal melakukan tugas yang dimaksud dalam beberapa kasus. Mungkin contoh yang akan sangat kritis dan mahal untuk gagal.

Kontrak vs. Tes unit

Argumen yang biasa pada yang satu ini adalah bahwa tes membuktikan keberadaan bug, sementara jenis (kontrak) membuktikan ketidakhadiran. F.ex. menggunakan tipe yang Anda tahu bahwa tidak ada jalur dalam program yang mungkin dapat memasok input yang tidak valid, sementara tes hanya bisa memberi tahu Anda bahwa jalur yang dicakup memang memberikan input yang benar.

Kontrak vs pola Objek Null

Sekarang ini setidaknya di taman bola yang sama. Bahasa seperti Scala dan Haskell telah sukses besar dengan pendekatan ini untuk menghilangkan referensi nol sepenuhnya dari program. (Bahkan jika Scala secara resmi mengizinkan nol, konvensi ini adalah untuk tidak pernah menggunakannya)

Jika Anda sudah menggunakan pola ini untuk menghilangkan NRE pada dasarnya Anda telah menghapus sumber kegagalan runtime terbesar, pada dasarnya ada cara kontrak memungkinkan Anda untuk melakukannya.

Perbedaannya mungkin bahwa kontrak memiliki opsi untuk secara otomatis meminta semua kode Anda untuk menghindari nol, dan dengan demikian memaksa Anda untuk menggunakan pola ini di lebih banyak tempat untuk lulus kompilasi.

Selain itu, kontrak juga memberi Anda fleksibilitas untuk menargetkan hal-hal di luar nol. Jadi jika Anda tidak lagi melihat NRE di bug Anda, Anda mungkin ingin menggunakan kontrak untuk mencekik masalah paling umum berikutnya yang mungkin Anda miliki. Mati satu per satu? Indeks di luar jangkauan?

Tapi...

Semua itu dikatakan. Saya setuju bahwa kontrak syntactic noise (dan bahkan noise struktural) menambah kode ini cukup besar dan dampak analisis terhadap pembangunan Anda tidak boleh diremehkan. Jadi, jika Anda memutuskan untuk menambahkan kontrak ke sistem Anda, mungkin akan bijaksana untuk melakukannya dengan sangat hati-hati dengan fokus yang sempit pada kelas bug mana yang coba diatasi.

John Nilsson
sumber
6
Itu jawaban pertama yang bagus pada Programmer. Senang memiliki partisipasi Anda dalam komunitas.
13

Saya tidak tahu dari mana pernyataan bahwa "itu tidak dan sering tidak dapat melakukan analisis statis" berasal. Bagian pertama dari pernyataan itu jelas-jelas salah. Yang kedua tergantung dari apa yang Anda maksud dengan "sering". Saya lebih suka mengatakan bahwa sering , ia melakukan analisis statis, dan jarang, gagal melakukannya. Dalam aplikasi bisnis biasa, jarang menjadi lebih dekat dengan tidak pernah .

Jadi ini dia, manfaat pertama:

Manfaat 1: analisis statis

Penegasan argumen dan argumen biasa memiliki kelemahan: mereka ditunda hingga kode dieksekusi. Di sisi lain, kontrak kode memanifestasikan diri pada tingkat yang jauh lebih awal, baik pada langkah pengkodean atau saat menyusun aplikasi. Semakin awal Anda menemukan kesalahan, semakin murah untuk memperbaikinya.

Manfaat 2: semacam dokumentasi yang selalu terkini

Kontrak kode juga menyediakan semacam dokumentasi yang selalu terkini. Jika komentar XML dari metode SetProductPrice(int newPrice)memberitahu bahwa newPriceharus lebih tinggi atau sama dengan nol, Anda mungkin berharap bahwa dokumentasi sudah mutakhir, tetapi Anda juga dapat menemukan bahwa seseorang mengubah metode sehingga newPrice = 0melempar ArgumentOutOfRangeException, tetapi tidak pernah mengubah dokumentasi yang sesuai. Mengingat korelasi antara kontrak kode dan kode itu sendiri, Anda tidak memiliki masalah dokumentasi yang tidak sinkron.

Jenis dokumentasi yang disediakan oleh kontrak kode juga berharga dengan cara yang sering, komentar XML tidak menjelaskan nilai yang dapat diterima dengan baik. Berapa kali adalah saya bertanya-tanya apakah nullatau string.Emptyatau \r\nmerupakan nilai yang berwenang untuk metode, dan XML komentar diam itu!

Kesimpulannya, tanpa kontrak kode, banyak potongan kode seperti itu:

Saya akan menerima beberapa nilai tetapi tidak yang lain, tetapi Anda harus menebak atau membaca dokumentasinya, jika ada. Sebenarnya, jangan membaca dokumentasinya: ini sudah ketinggalan zaman. Cukup lewati semua nilai dan Anda akan melihat yang membuat saya membuang pengecualian. Anda juga harus menebak rentang nilai yang dapat dikembalikan, karena meskipun saya akan memberi tahu lebih banyak kepada Anda tentang mereka, itu mungkin tidak benar, mengingat ratusan perubahan yang dibuat untuk saya selama beberapa tahun terakhir.

Dengan kontrak kode, itu menjadi:

Argumen judul dapat berupa string non-null dengan panjang 0..500. Bilangan bulat yang mengikuti adalah nilai positif, yang bisa menjadi nol hanya ketika string kosong. Akhirnya, saya akan mengembalikan IDefinitionobjek, tidak pernah null.

Manfaat 3: kontrak antarmuka

Manfaat ketiga adalah bahwa kontrak kode memberdayakan antarmuka. Katakanlah Anda memiliki sesuatu seperti:

public interface ICommittable
{
    public ICollection<AtomicChange> PendingChanges { get; }

    public void CommitChanges();

    ...
}

Bagaimana Anda, hanya menggunakan penegasan dan pengecualian, jaminan yang CommitChangesdapat dipanggil hanya ketika PendingChangestidak kosong? Bagaimana Anda menjamin itu PendingChangestidak pernah terjadi null?

Manfaat 4: menegakkan hasil suatu metode

Akhirnya, manfaat keempat adalah dapat Contract.Ensurehasil. Bagaimana jika, ketika menulis metode yang mengembalikan integer, saya ingin memastikan bahwa nilainya tidak pernah lebih rendah atau sama dengan nol? Termasuk lima tahun kemudian, setelah menderita banyak perubahan dari banyak pengembang? Segera setelah metode memiliki beberapa titik pengembalian, Asserts menjadi mimpi buruk pemeliharaan untuk itu.


Pertimbangkan kontrak kode tidak hanya sebagai sarana kebenaran kode Anda, tetapi cara yang lebih ketat untuk menulis kode. Dengan cara yang sama, seseorang yang menggunakan bahasa dinamis secara eksklusif mungkin bertanya mengapa Anda menerapkan tipe di tingkat bahasa, sementara Anda dapat melakukan hal yang sama dalam penegasan saat dibutuhkan. Anda bisa, tetapi pengetikan statis lebih mudah digunakan, lebih sedikit rawan kesalahan dibandingkan dengan banyak pernyataan, dan mendokumentasikan diri sendiri.

Perbedaan antara pengetikan dinamis dan pengetikan statis sangat dekat dengan perbedaan antara pemrograman biasa dan pemrograman berdasarkan kontrak.

rev MainMa
sumber
3

Saya tahu ini sedikit terlambat untuk pertanyaan, tetapi ada satu manfaat lain dari Kontrak Kode yang disebutkan

Kontrak diperiksa di luar metode

Ketika kami memiliki kondisi penjaga di dalam metode kami, itu adalah tempat di mana pemeriksaan terjadi dan di mana kesalahan dilaporkan. Kami kemudian mungkin harus menyelidiki jejak tumpukan untuk mencari tahu di mana sumber kesalahan sebenarnya.

Kontrak kode terletak di dalam metode, tetapi prasyarat diperiksa di luar metode ketika ada upaya untuk memanggil metode itu. Kontrak menjadi bagian dari metode dan menentukan apakah dapat dipanggil atau tidak. Itu berarti bahwa kami mendapatkan kesalahan yang dilaporkan jauh lebih dekat ke sumber masalah yang sebenarnya.

Jika Anda memiliki metode kontrak terlindungi yang disebut untuk banyak tempat, ini bisa menjadi manfaat nyata.

Alex White
sumber
2

Dua hal yang benar-benar:

  1. Dengan dukungan alat, VS dapat membuat data kontrak terpisah dari kecerdasan sehingga merupakan bagian dari bantuan lengkap otomatis.
  2. Ketika subclass menimpa metode Anda kehilangan semua cek Anda (yang seharusnya masih berlaku jika Anda mengikuti LSP) dengan kontrak mereka mengikuti kelas anak mereka secara otomatis.
stonemetal
sumber