Saya telah diberi tugas untuk mengimplementasikan Bahasa Spesifik Domain untuk alat yang mungkin menjadi sangat penting bagi perusahaan. Bahasa ini sederhana tetapi tidak sepele, itu sudah memungkinkan loop bersarang, penggabungan string, dll. Dan secara praktis yakin bahwa konstruksi lain akan ditambahkan seiring kemajuan proyek.
Saya tahu dari pengalaman bahwa menulis lexer / parser dengan tangan -kecuali tata bahasanya sepele- adalah proses yang memakan waktu dan rawan kesalahan. Jadi saya dibiarkan dengan dua opsi: generator parser à la yacc atau perpustakaan kombinator seperti Parsec. Yang pertama juga bagus tetapi saya memilih yang kedua karena berbagai alasan, dan mengimplementasikan solusi dalam bahasa fungsional.
Hasilnya cukup spektakuler di mata saya, kodenya sangat ringkas, elegan dan mudah dibaca / lancar. Saya akui itu mungkin terlihat agak aneh jika Anda tidak pernah memprogram apa pun selain java / c #, tapi kemudian ini akan berlaku untuk apa pun yang tidak ditulis dalam java / c #.
Namun pada beberapa titik, saya benar-benar diserang oleh seorang rekan kerja. Setelah melihat sekilas layar saya, dia menyatakan bahwa kodenya tidak bisa dipahami dan saya tidak harus menemukan parsing tetapi cukup gunakan stack dan String. Letakkan seperti yang dilakukan semua orang. Dia membuat banyak suara, dan saya tidak bisa meyakinkan dia, sebagian karena saya terkejut dan tidak memiliki penjelasan yang jelas, sebagian karena pendapatnya tidak berubah (tidak ada kata pun dimaksudkan). Saya bahkan menawarkan untuk menjelaskan bahasanya, tetapi tidak berhasil.
Saya yakin diskusi akan muncul kembali di depan manajemen, jadi saya menyiapkan beberapa argumen yang solid.
Ini adalah beberapa alasan pertama yang muncul di benak saya untuk menghindari solusi berbasis String.Split:
- Anda perlu banyak jika untuk menangani kasus-kasus khusus dan hal-hal dengan cepat lepas kendali
- banyak indeks array hardcoded membuat pemeliharaan menyakitkan
- sangat sulit untuk menangani hal-hal seperti pemanggilan fungsi sebagai argumen metode (mis. add ((tambahkan a, b), c)
- sangat sulit untuk memberikan pesan kesalahan yang bermakna jika terjadi kesalahan sintaks (sangat mungkin terjadi)
- Saya semua untuk kesederhanaan, kejelasan dan menghindari hal-hal smart-cryptic yang tidak perlu, tetapi saya juga percaya itu adalah kesalahan untuk merobohkan setiap bagian dari basis kode sehingga bahkan sirip burger pun dapat memahaminya. Itu argumen yang sama yang saya dengar untuk tidak menggunakan antarmuka, tidak mengadopsi pemisahan masalah, menyalin-menempel kode sekitar, dll. Minimal kompetensi teknis dan kemauan untuk belajar diperlukan untuk bekerja pada proyek perangkat lunak. (Saya tidak akan menggunakan argumen ini karena mungkin akan terdengar ofensif, dan memulai perang tidak akan membantu siapa pun)
Apa argumen favorit Anda yang menentang penguraian cara Cthulhu ? *
* tentu saja jika Anda dapat meyakinkan saya dia benar saya akan sangat bahagia juga
sumber
Jawaban:
Perbedaan kritis antara kedua pendekatan itu adalah, bahwa yang ia anggap sebagai satu-satunya cara yang benar adalah keharusan dan milik Anda bersifat deklaratif.
Pendekatan Anda secara eksplisit mendeklarasikan aturan, yaitu aturan tata bahasa (hampir) secara langsung dikodekan dalam kode Anda, dan parser library secara otomatis mengubah input mentah menjadi output yang diuraikan, sambil menjaga keadaan dan hal-hal lain yang sulit ditangani. Kode Anda ditulis dalam satu lapisan abstraksi, yang bertepatan dengan domain masalah: parsing. Masuk akal untuk mengasumsikan kebenaran parsec, yang berarti satu-satunya ruang untuk kesalahan di sini adalah, bahwa definisi tata bahasa Anda salah. Tetapi sekali lagi Anda memiliki objek aturan yang sepenuhnya memenuhi syarat dan mereka mudah diuji secara terpisah. Juga mungkin perlu dicatat, bahwa parser perpustakaan dewasa dikirimkan dengan satu fitur penting: pelaporan kesalahan. Pemulihan kesalahan yang layak saat penguraian salah tidak sepele. Sebagai buktinya, saya memanggil PHP
parse error, unexpected T_PAAMAYIM_NEKUDOTAYIM
: DPendekatannya memanipulasi string, secara eksplisit mempertahankan status dan mengangkat input mentah secara manual ke input yang diuraikan. Anda harus menulis semuanya sendiri, termasuk pelaporan kesalahan. Dan ketika terjadi kesalahan, Anda benar-benar tersesat.
Ironisnya adalah bahwa kebenaran parser yang ditulis dengan pendekatan Anda relatif mudah dibuktikan. Dalam kasusnya, itu hampir mustahil.
Pendekatan Anda adalah yang lebih sederhana. Yang menghalangi hanyalah baginya untuk sedikit memperluas cakrawala. Hasil dari pendekatannya akan selalu berbelit-belit, tidak peduli seberapa luas cakrawala Anda.
Sejujurnya, bagiku itu terdengar, bahwa lelaki itu hanyalah orang bodoh yang bodoh, yang menderita sindrom blub , cukup sombong untuk menganggap Anda salah dan berteriak pada Anda, jika dia tidak mengerti Anda.
Namun pada akhirnya, pertanyaannya adalah: siapa yang harus memeliharanya? Jika itu Anda, maka itu panggilan Anda, tidak peduli apa kata orang. Jika itu adalah dia, maka hanya ada dua kemungkinan: Temukan cara untuk membuatnya mengerti perpustakaan parser atau menulis parser penting untuknya. Saya sarankan Anda menghasilkannya dari struktur parser Anda: D
sumber
Tata bahasa ekspresi parsing (seperti pendekatan parser Packrat) atau kombinator parser tidak menciptakan kembali parsing. Ini adalah teknik mapan di dunia pemrograman fungsional dan, di tangan kanan, itu bisa lebih mudah dibaca daripada alternatif. Saya telah melihat demonstrasi PEG yang cukup meyakinkan di C # beberapa tahun yang lalu yang benar-benar menjadikannya alat pertama saya untuk tata bahasa yang relatif sederhana.
Jika Anda memiliki solusi yang elegan dengan menggunakan parser combinator atau PEG, itu harus menjadi penjualan yang relatif mudah: itu cukup dapat diperpanjang, biasanya relatif mudah dibaca setelah Anda mengatasi ketakutan Anda terhadap pemrograman fungsional, dan kadang-kadang lebih mudah dibaca daripada generator parser biasa alat menawarkan, meskipun itu sangat tergantung pada tata bahasa dan tingkat pengalaman yang Anda miliki dengan kedua set alat. Menulis tes juga cukup mudah. Tentu saja, ada beberapa ambiguitas tata bahasa yang dapat menghasilkan kinerja penguraian yang sangat buruk dalam skenario kasus terburuk (atau banyak konsumsi memori dengan Packrat), tetapi kasus rata-rata cukup baik dan sebenarnya beberapa ambiguitas tata bahasa lebih baik ditangani dengan PEG daripada LALR, karena Saya ingat.
Menggunakan Split dan tumpukan bekerja dengan beberapa tata bahasa yang lebih sederhana daripada PEG atau dapat mendukung, tetapi sangat mungkin bahwa seiring waktu Anda akan menemukan kembali keturunan rekursif dengan buruk, atau Anda akan memiliki serangkaian perilaku serpihan yang akan Anda bandel. bantuan untuk pengajuan dengan biaya kode yang sangat tidak terstruktur. Jika Anda hanya memiliki aturan tokenization sederhana, itu mungkin tidak terlalu buruk, tetapi ketika Anda menambahkan kompleksitas, itu mungkin akan menjadi solusi yang paling tidak dapat dipertahankan. Saya akan meraih generator parser sebagai gantinya.
Secara pribadi, kecenderungan pertama saya ketika saya perlu membangun DSL adalah menggunakan sesuatu seperti Boo (.Net) atau Groovy (JVM), karena saya mendapatkan semua kekuatan bahasa pemrograman yang ada dan kemampuan penyesuaian yang luar biasa dengan membangun makro dan penyesuaian sederhana ke pipeline compiler, tanpa harus mengimplementasikan hal-hal yang membosankan yang akhirnya akan saya lakukan jika saya mulai dari nol (loop, variabel, model objek, dll). Jika saya berada di toko yang melakukan pengembangan Ruby atau Lisp, saya hanya akan menggunakan idiom yang masuk akal di sana (metaprogramming, dll.)
Tapi saya menduga masalah Anda sebenarnya adalah tentang budaya atau ego. Apakah Anda yakin rekan kerja Anda tidak akan takut jika Anda menggunakan Antlr atau Flex / Bison? Saya menduga bahwa "berdebat" untuk solusi Anda mungkin merupakan pertempuran yang kalah; Anda mungkin perlu menghabiskan lebih banyak waktu melakukan pendekatan yang lebih lunak yang menggunakan teknik membangun konsensus daripada menarik bagi otoritas manajemen lokal Anda. Pasangkan pemrograman, dan tunjukkan seberapa cepat Anda dapat mengubah penyesuaian pada tata bahasa tanpa mengorbankan pemeliharaan, dan melakukan brownbag untuk menjelaskan teknik, sejarahnya, dan sebagainya, mungkin lebih jauh dari 10 poin-poin dan "T&J kasar" di beberapa pertemuan konfrontatif.
sumber
Saya tidak berpengalaman dalam algoritma parsing dan sejenisnya, tapi saya pikir bukti puding ada di makan. Jadi, jika semuanya gagal, Anda bisa menawarkannya untuk mengimplementasikan parser dengan caranya. Kemudian
Agar pengujian benar-benar adil, Anda mungkin ingin kedua solusi mengimplementasikan API yang sama, dan menggunakan testbed umum (atau kerangka kerja unit pengujian yang dikenal oleh Anda berdua). Anda berdua dapat menulis sejumlah dan jenis kasus uji fungsional dan memastikan bahwa solusinya sendiri melewati semuanya. Dan tentu saja, idealnya tidak satu pun dari Anda harus memiliki akses ke implementasi yang lain sebelum batas waktu. Tes yang menentukan kemudian akan menguji silang kedua solusi menggunakan test suite yang dikembangkan oleh pengembang lain .
sumber
Anda telah menanyakan ini seolah-olah Anda memiliki pertanyaan teknis, tetapi karena Anda mungkin sudah tahu, tidak ada pertanyaan teknis di sini. Pendekatan Anda jauh lebih unggul daripada meretas sesuatu di tingkat karakter.
Masalah sebenarnya adalah bahwa kolega Anda (mungkin lebih berpengalaman) tidak aman, dan merasa terancam oleh pengetahuan Anda. Anda tidak akan membujuknya dengan argumen teknis ; itu hanya akan membuatnya lebih defensif. Alih-alih, Anda harus menemukan cara untuk mengurangi ketakutannya. Saya tidak bisa menawarkan banyak saran, tetapi Anda mungkin mencoba menunjukkan penghargaan yang tinggi atas pengetahuannya tentang kode warisan.
Akhirnya, jika manajer Anda setuju dengan argumen teknisnya dan membuang solusi Anda, maka saya pikir Anda harus mencari posisi lain. Jelas Anda akan lebih berharga, dan lebih tinggi nilainya, dalam organisasi yang lebih canggih.
sumber
Saya akan singkat:
Mengurai cara Cthulhu itu sulit. Itu argumen paling sederhana dan paling meyakinkan untuk menentangnya.
Ini dapat melakukan trik untuk bahasa sederhana; katakanlah, bahasa biasa. Mungkin itu tidak akan lebih mudah daripada ekspresi reguler.
Ini juga dapat melakukan trik untuk bahasa yang sedikit lebih rumit.
Namun, saya ingin melihat parser Cthulhu untuk bahasa apa pun dengan bersarang, atau hanya "secara signifikan menyatakan" - ekspresi matematika, atau contoh Anda (panggilan fungsi bersarang).
Bayangkan apa yang akan terjadi jika seseorang mencoba cthulhu parser untuk bahasa (non-sepele konteks) seperti itu. Asalkan dia cukup pintar untuk menulis parser yang benar, saya berani bertaruh bahwa selama pengkodean dia akan "menemukan" tokenizaton pertama, dan kemudian parsing keturunan rekursif - dalam beberapa bentuk.
Setelah itu, masalahnya sederhana: "Hei, kamu sudah menulis sesuatu yang disebut parser keturunan rekursif! Tahukah Anda bahwa itu dapat dihasilkan secara otomatis dari deskripsi tata bahasa yang sederhana, seperti halnya ekspresi reguler?
Singkat cerita:
Satu-satunya hal yang dapat menghentikan seseorang untuk menggunakan pendekatan yang beradab adalah ketidaktahuan mereka akan hal itu.
sumber
Mungkin bekerja pada semantik DSL yang baik juga penting (masalah sintaksis, tetapi juga semantik). Jika Anda tidak terbiasa dengan masalah ini, saya sarankan membaca beberapa buku, seperti Bahasa Pemrograman Pragmatik (oleh M.Scott) dan Christian Queinnec. Gangguan Dalam Potongan Kecil . Cambridge University Press, 1996.
Membaca makalah terbaru dalam konferensi DSL, mis. DSL2011 juga harus membantu.
Merancang & mengimplementasikan Bahasa Spesifik Domain itu sulit (dan sebagian besar kesulitannya tidak menguraikan!).
Saya tidak benar-benar mengerti apa yang Anda maksud dengan menguraikan cara Cthulhu ; Saya kira Anda bermaksud mengurai dengan cara yang entah bagaimana aneh.
sumber