Pemrograman bersih saat menulis kode ilmiah

169

Saya tidak benar-benar menulis proyek besar. Saya tidak memelihara database besar atau berurusan dengan jutaan baris kode.

Kode saya terutama "jenis scripting" jenis - hal untuk menguji fungsi matematika, atau untuk mensimulasikan sesuatu - "pemrograman ilmiah". Program terpanjang yang saya kerjakan hingga saat ini adalah beberapa ratus baris kode, dan sebagian besar program yang saya kerjakan sekitar 150.

Kode saya juga omong kosong. Saya menyadari ini beberapa hari yang lalu ketika saya mencoba untuk menemukan file yang saya tulis beberapa waktu yang lalu tetapi saya mungkin menimpa dan bahwa saya tidak menggunakan kontrol versi, yang mungkin membuat banyak dari Anda merasa ngeri kesakitan karena kebodohan saya.

Gaya kode saya berbelit-belit dan dipenuhi dengan komentar usang yang mencatat cara alternatif untuk melakukan sesuatu atau dengan baris kode yang disalin. Sementara nama variabel selalu dimulai dengan sangat bagus dan deskriptif, karena saya menambahkan atau mengubah hal-hal sesuai misalnya, sesuatu yang baru ingin diuji seseorang, kode akan ditimpa di atas dan ditimpa dan karena saya merasa hal ini harus diuji dengan cepat sekarang karena saya punya kerangka saya mulai menggunakan nama variabel jelek dan file masuk ke pot.

Dalam proyek yang sedang saya kerjakan sekarang, saya berada dalam fase di mana semua ini kembali menggigit saya secara besar-besaran. Tetapi masalahnya adalah (selain menggunakan kontrol versi, dan membuat file baru untuk setiap iterasi baru dan merekam semuanya dalam file teks di suatu tempat, yang mungkin akan membantu situasi secara dramatis) Saya tidak benar-benar tahu bagaimana cara melanjutkan peningkatan gaya coding saya yang sebenarnya.

Apakah pengujian unit diperlukan untuk menulis potongan kode yang lebih kecil? Bagaimana dengan OOP? Apa jenis pendekatan yang baik untuk menulis kode yang baik dan bersih dengan cepat ketika melakukan "pemrograman ilmiah" sebagai lawan bekerja pada proyek yang lebih besar?

Saya mengajukan pertanyaan ini karena seringkali, pemrograman itu sendiri tidak super kompleks. Ini lebih tentang matematika atau sains yang saya uji atau teliti dengan pemrograman. Misalnya, apakah kelas diperlukan ketika dua variabel dan suatu fungsi mungkin bisa mengatasinya? (Pertimbangkan ini juga umumnya situasi di mana kecepatan program lebih disukai berada di ujung yang lebih cepat - ketika Anda menjalankan 25.000.000 langkah waktu simulasi, Anda agak menginginkannya.)

Mungkin ini terlalu luas, dan jika demikian, saya minta maaf, tetapi melihat buku-buku pemrograman, mereka sering kali ditujukan pada proyek yang lebih besar. Kode saya tidak perlu OOP, dan itu sudah sangat pendek sehingga tidak seperti "oh, tapi file akan berkurang seribu baris jika kita melakukannya!" Saya ingin tahu bagaimana "memulai" dan memprogram dengan bersih pada proyek-proyek yang lebih kecil dan lebih cepat ini.

Saya akan dengan senang hati memberikan rincian yang lebih spesifik, tetapi semakin umum sarannya, semakin berguna, saya pikir. Saya pemrograman dengan Python 3.


Seseorang menyarankan duplikat. Biarkan saya jelaskan saya tidak berbicara tentang mengabaikan standar pemrograman standar. Jelas, ada alasan standar itu ada. Tetapi di sisi lain, apakah masuk akal untuk menulis kode yang mengatakan OOP ketika beberapa hal standar dapat dilakukan, akan jauh lebih cepat untuk ditulis, dan akan memiliki tingkat keterbacaan yang sama karena pendeknya standar. program?

Ada pengecualian. Lebih jauh, mungkin ada standar untuk pemrograman ilmiah di luar standar biasa. Saya bertanya tentang itu juga. Ini bukan tentang apakah standar pengkodean normal harus diabaikan ketika menulis kode ilmiah, ini tentang menulis kode ilmiah bersih!


Memperbarui

Hanya berpikir saya akan menambahkan jenis pembaruan "tidak-cukup-satu-minggu-kemudian". Semua saran Anda sangat membantu. Saya sekarang menggunakan kontrol versi - git, dengan git kraken untuk antarmuka grafis. Ini sangat mudah digunakan, dan telah membersihkan file saya secara drastis - tidak perlu lagi ada file lama, atau kode versi lama berkomentar "berjaga-jaga".

Saya juga menginstal pylint dan menjalankannya pada semua kode saya. Satu file mendapat skor negatif pada awalnya; Aku bahkan tidak yakin bagaimana itu bisa terjadi. File utama saya dimulai pada skor ~ 1,83 / 10 dan sekarang berada di ~ 9,1 / 10. Semua kode sekarang sesuai dengan standar. Saya juga menabraknya dengan mata saya sendiri memperbarui nama variabel yang telah ... uhm ... salah, dan mencari bagian untuk refactor.

Secara khusus, saya mengajukan pertanyaan baru-baru ini di situs ini tentang refactoring salah satu fungsi utama saya, dan sekarang jauh lebih bersih dan jauh lebih pendek: alih-alih fungsi yang panjang, bengkak, jika diisi / diisi, sekarang kurang dari setengah ukuran dan lebih mudah untuk mencari tahu apa yang sedang terjadi.

Langkah saya berikutnya adalah menerapkan semacam "unit test". Maksud saya file yang bisa saya jalankan di file utama saya yang melihat semua fungsi di dalamnya dengan pernyataan tegas dan coba / pengecualian, yang mungkin bukan cara terbaik untuk melakukannya, dan menghasilkan banyak kode duplikat, tetapi saya akan terus membaca dan mencoba mencari cara untuk melakukannya dengan lebih baik.

Saya juga telah memperbarui secara signifikan dokumentasi yang telah saya tulis, dan menambahkan file tambahan seperti spreadsheet excel, dokumentasi, dan makalah terkait ke repositori github. Agak terlihat seperti proyek pemrograman nyata sekarang.

Jadi ... saya kira ini semua untuk mengatakan: terima kasih .

heather
sumber
9
Anda mungkin menemukan jawaban pada Apakah layak untuk menulis unit test untuk kode penelitian ilmiah? berguna.
Mark Booth
8
Jika Anda secara aktif ingin meningkatkan kode Anda, Anda dapat mempertimbangkan untuk memposting beberapa di Ulasan Kode . Komunitas di sana dengan senang hati akan membantu Anda dengan itu.
hoffmale
7
Ketika Anda mengatakan "selain menggunakan kontrol versi, dan membuat file baru untuk setiap iterasi baru dan merekam semuanya dalam file teks di suatu tempat" oleh "dan" maksud Anda "atau" karena jika Anda menggunakan kontrol versi, Anda seharusnya tidak bisa menyalin versi paste. Intinya adalah bahwa kontrol versi membuat semua versi lama untuk Anda
Richard Tingle
2
@ mathreadler Saya tidak berpikir Anda cukup mengerti. Ya, hanya saya yang mungkin setiap orang akan benar-benar membaca dan mengacaukan kode (meskipun Anda tidak pernah tahu, dan saya memiliki seseorang yang bekerja sama dengan saya yang dapat memprogram, meskipun dalam bahasa yang berbeda) ... tetapi kodenya masih sampah. Saya harus membacanya nanti dan mencari tahu lagi apa yang saya lakukan. Ini adalah masalah, dan saya bisa memberikan kesaksian karena saya mengalami efeknya sekarang, dan segalanya menjadi lebih mudah karena saya telah menerapkan kontrol versi dan teknik-teknik lain yang disarankan di sini.
heather

Jawaban:

163

Ini adalah masalah yang cukup umum bagi para ilmuwan. Saya sudah sering melihatnya, dan selalu bermula dari kenyataan bahwa pemrograman adalah sesuatu yang Anda pilih sebagai alat untuk melakukan pekerjaan Anda.

Jadi skrip Anda berantakan. Saya akan menentang akal sehat dan mengatakan bahwa, dengan asumsi Anda pemrograman sendiri, ini tidak terlalu buruk! Anda tidak akan pernah menyentuh sebagian besar dari apa yang Anda tulis lagi, jadi menghabiskan terlalu banyak waktu untuk menulis kode cantik alih-alih menghasilkan "nilai" (jadi hasil skrip Anda) tidak akan berbuat banyak untuk Anda.

Namun, akan ada saat di mana Anda harus kembali ke sesuatu yang Anda lakukan dan melihat dengan tepat bagaimana sesuatu itu bekerja. Selain itu, jika ilmuwan lain perlu meninjau kode Anda, sangat penting baginya untuk sejelas dan sesingkat mungkin, sehingga semua orang dapat memahaminya.

Masalah utama Anda adalah keterbacaan, jadi inilah beberapa tips untuk meningkatkan:

Nama variabel:

Para ilmuwan senang menggunakan notasi singkat. Semua persamaan matematika biasanya menggunakan huruf tunggal sebagai variabel, dan saya tidak akan terkejut melihat banyak dan banyak variabel sangat pendek dalam kode Anda. Ini menyakitkan keterbacaan banyak. Ketika Anda akan kembali ke kode Anda, Anda tidak akan mengingat apa yang diwakili oleh y, i dan x2, dan Anda akan menghabiskan banyak waktu untuk mencari tahu. Coba sebutkan variabel Anda secara eksplisit, menggunakan nama yang mewakili apa sebenarnya variabel itu.

Bagi kode Anda menjadi beberapa fungsi:

Sekarang setelah Anda mengganti nama semua variabel Anda, persamaan Anda tampak mengerikan, dan panjangnya banyak baris.

Alih-alih meninggalkannya di program utama Anda, pindahkan persamaan itu ke fungsi yang berbeda, dan beri nama sesuai. Sekarang alih-alih memiliki garis kode yang besar dan kacau, Anda akan memiliki instruksi singkat yang memberi tahu Anda dengan tepat apa yang terjadi dan persamaan apa yang Anda gunakan. Ini meningkatkan kedua program utama Anda, karena Anda bahkan tidak perlu melihat persamaan aktual untuk mengetahui apa yang Anda lakukan, dan kode persamaan itu sendiri, seperti dalam fungsi terpisah Anda dapat memberi nama variabel Anda seperti yang Anda inginkan, dan kembali ke satu huruf yang lebih akrab.

Pada garis pemikiran ini, cobalah untuk mencari tahu semua bagian kode yang mewakili sesuatu, terutama jika sesuatu itu adalah sesuatu yang harus Anda lakukan berulang kali dalam kode Anda, dan membaginya menjadi beberapa fungsi. Anda akan mengetahui bahwa kode Anda akan dengan cepat menjadi lebih mudah dibaca, dan Anda akan dapat menggunakan fungsi yang sama tanpa menulis lebih banyak kode.

Menghitung kue, jika fungsi-fungsi itu diperlukan di lebih dari program Anda, Anda bisa membuat perpustakaan untuk mereka, dan Anda akan selalu memilikinya.

Variabel global:

Kembali ketika saya masih pemula, saya pikir ini adalah cara yang bagus untuk menyampaikan data yang saya butuhkan di banyak titik program saya. Ternyata ada banyak cara lain untuk menyebarkan hal-hal, dan satu-satunya hal variabel global lakukan adalah membuat orang sakit kepala, karena jika Anda pergi ke titik acak program Anda, Anda tidak akan pernah tahu kapan nilai itu terakhir digunakan atau diedit, dan melacaknya akan menyebalkan. Cobalah untuk menghindarinya sedapat mungkin.

Jika fungsi Anda perlu mengembalikan atau memodifikasi beberapa nilai, buat kelas dengan nilai-nilai itu dan turunkan sebagai parameter, atau buat fungsi mengembalikan beberapa nilai (dengan nama tupel) dan tetapkan nilai-nilai itu dalam kode pemanggil.

Kontrol Versi

Ini tidak secara langsung meningkatkan keterbacaan, tetapi membantu Anda melakukan semua hal di atas. Setiap kali Anda melakukan beberapa perubahan, komit ke kontrol versi (repositori Git lokal akan cukup baik), dan jika sesuatu tidak berfungsi, lihat apa yang Anda ubah atau putar kembali! Ini akan membuat refactoring kode Anda lebih mudah, dan akan menjadi jaring pengaman jika Anda tidak sengaja memecahkan barang.

Mempertahankan semua ini dalam pikiran akan memungkinkan Anda untuk menulis kode yang jelas dan lebih efektif, dan juga akan membantu Anda menemukan kemungkinan kesalahan lebih cepat, karena Anda tidak perlu mengarungi fungsi-fungsi raksasa dan variabel-variabel yang berantakan.

BgrWorker
sumber
56
Saran yang sangat baik. Namun saya tidak dapat memilih untuk komentar "yang tidak terlalu buruk". Sangat buruk. Skrip ilmiah berkualitas rendah adalah masalah besar untuk reproduksibilitas dalam analisis data dan sering menjadi sumber kesalahan dalam analisis. Menulis kode yang baik berharga tidak hanya agar Anda dapat memahaminya nanti tetapi juga agar Anda dapat menghindari kesalahan sejak awal.
Jack Aidley
22
Jika kode tersebut merupakan implementasi dari rumus yang terkenal, maka nama variabel satu huruf dan hal itu mungkin merupakan hal yang benar untuk dilakukan. Bergantung pada audiens ... dan lebih tepatnya, apakah pembaca diharapkan sudah tahu apa arti namanya.
cHao
11
@ cHao masalahnya bukan ketika variabel-variabel tersebut dicolokkan dalam rumus (maka saran "ganti nama mereka di dalam fungsi"), tetapi ketika mereka membaca dan dimanipulasi di luarnya, dan ketika mereka mulai bertentangan dengan variabel lain di telepon (misalnya, saya pernah melihat orang yang membutuhkan tiga variabel "x"
beri
4
"Aku akan melawan akal sehat ..." Tidak, kamu tidak. Anda menentang dogma yang ada, yang dengan sendirinya bertentangan dengan akal sehat. ;) Ini semua saran yang sangat masuk akal.
jpmc26
3
Sebagai (mantan) programmer ilmiah, saya biasanya mengadopsi aturan tiga. Jika saya akhirnya menulis kode yang sama tiga kali, fungsionalitasnya menjadi lebih baik dan ditulis dalam modul terpisah dengan dokumentasi (seringkali hanya komentar, tapi itu sudah cukup). Ini membatasi kekacauan pemrograman ad-hoc, dan memungkinkan saya untuk membangun perpustakaan yang dapat saya kembangkan di masa depan.
rcollyer
141

Fisikawan di sini. Pernah ke sana.

Saya berpendapat bahwa masalah Anda bukan tentang pilihan alat atau paradigma pemrograman (pengujian unit, OOP, apa pun). Ini tentang sikap , pola pikir. Fakta bahwa nama variabel Anda dipilih dengan baik pada awalnya dan akhirnya menjadi omong kosong cukup mengungkapkan. Jika Anda menganggap kode Anda sebagai "jalankan sekali, lalu buang", maka itu pasti akan berantakan. Jika Anda menganggapnya sebagai produk kerajinan dan cinta, itu akan menjadi indah.

Saya percaya hanya ada satu resep untuk menulis kode bersih: tuliskan untuk manusia yang akan membacanya, bukan untuk penerjemah yang akan menjalankannya. Penerjemah tidak peduli jika kode Anda berantakan, tetapi pembaca manusia tidak peduli.

Anda seorang ilmuwan. Anda mungkin dapat menghabiskan banyak waktu memoles artikel ilmiah. Jika draf pertama Anda terlihat berbelit-belit, Anda akan refactor sampai logika mengalir dengan cara yang paling alami. Anda ingin kolega Anda membacanya dan menemukan argumen yang jelas. Anda ingin siswa Anda dapat belajar darinya.

Menulis kode bersih sama persis . Pikirkan kode Anda sebagai penjelasan terperinci dari suatu algoritma yang kebetulan hanya bisa dibaca mesin. Bayangkan Anda akan mempublikasikannya sebagai artikel yang akan dibaca orang. Anda bahkan akan menunjukkannya di sebuah konferensi dan mengajak hadirin melewatinya baris demi baris. Sekarang, latih presentasi Anda . Ya, baris demi baris ! Memalukan, bukan? Jadi bersihkan slide Anda (err ... maksud saya, kode Anda), dan latih kembali. Ulangi sampai Anda puas dengan hasilnya.

Akan lebih baik jika, setelah latihan, Anda dapat menunjukkan kode Anda kepada orang-orang nyata daripada hanya orang-orang imajiner dan diri masa depan Anda. Melewatinya baris demi baris disebut "kode berjalan", dan itu bukan praktik konyol.

Tentu saja, semua ini harus dibayar. Menulis kode bersih membutuhkan lebih banyak waktu daripada menulis kode yang bisa dibuang. Hanya Anda yang dapat mengevaluasi apakah manfaatnya lebih besar daripada biaya untuk kasus penggunaan khusus Anda.

Adapun alat, saya katakan sebelumnya mereka tidak begitu penting. Namun, jika saya harus memilih satu, saya akan mengatakan kontrol versi adalah yang paling berguna.

Edgar Bonet
sumber
32
«Menulis kode bersih persis sama [seperti menulis artikel yang jelas].» Saya sepenuhnya mendukung itu, well meletakkan!
remaja
43
Ini adalah sesuatu yang lupa dikatakan oleh sebagian besar programmer profesional karena sangat jelas. Kode Anda selesai saat dapat dibaca dan dimodifikasi oleh programmer lain. Tidak ketika dijalankan dan menghasilkan output yang benar. OP perlu menghabiskan dan satu jam ekstra per skrip, refactoring dan mengomentari kodenya agar dapat dibaca manusia.
UEFI
31
Meskipun menulis kode bersih memang membutuhkan lebih banyak waktu daripada menulis kode sekali pakai, jauh lebih penting adalah bahwa membaca kode bersih membutuhkan lebih banyak waktu daripada membaca kode bersih.
user949300
3
@UEFI Tidak, itu sesuatu yang kebanyakan programmer bahkan tidak sadari. Atau tidak peduli.
jpmc26
2
Setuju 100%. Ahli statistik berubah menjadi programmer, jadi saya melakukan pemrograman 'ilmiah' dalam jumlah yang cukup di tempat kerja. Hapus kode, dengan komentar yang berarti adalah penyelamat ketika Anda harus kembali ke kode 1, 4, atau 12 bulan kemudian. Membaca kode memberi tahu Anda apa yang dilakukan kode. Membaca komentar memberi tahu Anda apa yang seharusnya dilakukan kode.
railsdog
82

Kontrol versi mungkin akan memberi Anda hasil maksimal. Ini bukan hanya untuk penyimpanan jangka panjang, ini bagus untuk melacak eksperimen jangka pendek Anda dan kembali ke versi terakhir yang berfungsi, membuat catatan sepanjang jalan.

Berikutnya yang paling berguna adalah unit test. Satu hal tentang pengujian unit adalah bahkan basis kode dengan jutaan baris kode diuji unit satu fungsi pada suatu waktu. Pengujian unit dilakukan dalam skala kecil, pada tingkat abstraksi terendah. Itu berarti secara mendasar tidak ada perbedaan antara tes unit yang ditulis untuk basis kode kecil dan yang digunakan untuk yang besar. Hanya ada lebih banyak dari mereka.

Tes unit adalah cara terbaik agar tidak merusak sesuatu yang sudah berfungsi saat Anda memperbaiki sesuatu yang lain, atau setidaknya untuk memberi tahu Anda dengan cepat ketika Anda melakukannya. Mereka sebenarnya lebih berguna ketika Anda tidak sebagai seorang programmer yang terampil, atau tidak tahu bagaimana atau tidak ingin menulis lebih banyak kode verbose yang disusun untuk membuat kesalahan lebih kecil atau lebih jelas.

Antara kontrol versi dan penulisan unit test saat Anda berjalan, kode Anda secara alami akan menjadi jauh lebih bersih. Teknik-teknik lain untuk pengkodean yang lebih bersih dapat dipelajari ketika Anda mencapai dataran tinggi.

Karl Bielefeldt
sumber
78
Saya secara relijius menguji sebagian besar kode saya, tetapi saya menemukan bahwa pengujian unit eksplorasi, kode ilmiah kurang berguna . Metodologi ini pada dasarnya tidak berfungsi di sini. Saya tidak tahu ada ilmuwan komputasi di bidang saya yang unit-tes kode analisis mereka. Saya tidak yakin apa alasan ketidakcocokan ini, tetapi salah satu alasannya adalah bahwa, kecuali untuk unit-unit sepele, sulit atau tidak mungkin untuk membuat kasus uji yang baik.
Konrad Rudolph
22
@KonradRudolph, trik dalam kasus-kasus tersebut mungkin merupakan pemisahan yang bersih antara bagian-bagian kode Anda yang memiliki perilaku yang jelas (baca input ini, hitung nilai ini) dari bagian-bagian kode Anda yang benar-benar eksplorasi atau beradaptasi dengan misalnya beberapa output atau visualisasi yang dapat dibaca manusia. Masalahnya di sini adalah kemungkinan bahwa pemisahan keprihatinan yang buruk menyebabkan pengaburan garis-garis tersebut, yang mengarah pada persepsi bahwa pengujian unit dalam konteks ini tidak mungkin, yang membawa Anda kembali ke awal dalam siklus berulang.
Semut P
18
Di samping catatan, kontrol versi juga berfungsi cukup baik untuk dokumen LaTeX, karena formatnya sesuai dengan perbedaan teks. Dengan cara ini, Anda dapat memiliki repositori untuk makalah Anda dan kode yang mendukungnya. Saya sarankan melihat ke kontrol versi terdistribusi, seperti Git. Ada sedikit kurva pembelajaran, tetapi begitu Anda memahaminya, Anda memiliki cara bersih yang bagus untuk beralih pada pengembangan Anda dan Anda memiliki beberapa opsi menarik untuk menggunakan platform seperti Github, yang menawarkan akun tim gratis untuk akademisi .
Dan Bryant
12
@AntP Mungkin saja tidak ada banyak kode yang dapat dire-refrukturisasi secara bermakna menjadi unit yang dapat diuji yang terdefinisi dengan baik. Banyak kode ilmiah pada dasarnya merekatkan sekelompok perpustakaan bersama. Perpustakaan-perpustakaan ini sudah akan diuji dengan baik dan terstruktur dengan rapi, artinya penulis hanya perlu menulis "lem", dan menurut pengalaman saya, hampir tidak mungkin untuk menulis unit test untuk lem yang tidak bersifat tautologis.
James_pic
7
"Antara kontrol versi dan penulisan unit test saat Anda berjalan, kode Anda secara alami akan menjadi jauh lebih bersih." Ini tidak benar. Saya bisa membuktikannya secara pribadi. Tak satu pun dari alat-alat ini menghentikan Anda dari menulis kode jelek, dan khususnya, menulis tes jelek di atas kode jelek hanya membuatnya lebih sulit untuk dibersihkan. Tes bukanlah peluru perak ajaib, dan berbicara seperti itu adalah hal yang mengerikan untuk dilakukan untuk setiap pengembang yang masih belajar (yang semuanya orang). Kontrol versi umumnya tidak pernah menyebabkan kerusakan pada kode itu sendiri seperti halnya pengujian yang buruk.
jpmc26
29

(Selain menggunakan kontrol versi, dan membuat file baru untuk setiap iterasi baru dan merekam semuanya dalam file teks di suatu tempat, yang mungkin akan membantu situasi secara dramatis)

Anda mungkin akan menemukan ini sendiri, tetapi jika Anda harus " merekam semuanya dalam file teks di suatu tempat " Anda tidak menggunakan sistem kontrol versi secara maksimal. Gunakan sesuatu seperti Subversion, git, atau Mercurial dan tulis pesan komit yang baik dengan setiap komit dan Anda akan memiliki log yang melayani tujuan file teks tetapi tidak dapat dipisahkan dari repositori.

Selain itu, menggunakan kontrol versi adalah hal paling penting yang dapat Anda lakukan untuk alasan yang tidak disebutkan oleh jawaban yang ada: reproduksibilitas hasil . Jika Anda dapat menggunakan pesan log atau menambahkan catatan ke hasil dengan nomor revisi maka Anda dapat yakin dapat membuat ulang hasil, dan Anda akan lebih baik ditempatkan untuk mempublikasikan kode dengan kertas.

Apakah pengujian unit diperlukan untuk menulis potongan kode yang lebih kecil? Bagaimana dengan OOP? Apa jenis pendekatan yang baik untuk menulis kode yang baik dan bersih dengan cepat ketika melakukan "pemrograman ilmiah" sebagai lawan bekerja pada proyek yang lebih besar?

Pengujian unit tidak pernah diperlukan, tetapi akan berguna jika (a) kode cukup modular sehingga Anda dapat menguji unit daripada keseluruhannya; (B) Anda dapat membuat tes. Idealnya Anda dapat menulis output yang diharapkan dengan tangan daripada menghasilkannya dengan kode, meskipun menghasilkannya dengan kode setidaknya dapat memberi Anda tes regresi yang memberi tahu Anda apakah ada sesuatu yang mengubah perilakunya. Pertimbangkan apakah tes lebih cenderung buggy daripada kode yang mereka uji.

OOP adalah alat. Gunakan jika itu membantu, tetapi itu bukan satu-satunya paradigma. Saya berasumsi bahwa Anda hanya benar-benar tahu pemrograman prosedural: jika itu masalahnya, maka dalam konteks yang dijelaskan saya pikir Anda akan mendapat manfaat lebih banyak dari mempelajari pemrograman fungsional daripada OOP, dan khususnya disiplin menghindari efek samping jika memungkinkan. Python dapat ditulis dalam gaya yang sangat fungsional.

Peter Taylor
sumber
4
+1 untuk pesan komit; mereka seperti komentar yang tidak bisa kedaluwarsa karena mereka terikat pada versi kode ketika mereka benar-benar berlaku. Untuk memahami kode lama Anda, lebih mudah untuk melihat sejarah proyek (jika perubahan dilakukan pada granularitas yang masuk akal) daripada membaca komentar yang sudah ketinggalan zaman.
Silly Freak
Subversi, git, dan Mercurial tidak sepadan. Saya sangat menganjurkan menggunakan Git (atau Mercurial) dengan repositori lokal di atas Subversion. Dengan solo coder, kelemahan Subversion tidak terlalu menjadi masalah, tetapi itu bukan alat yang hebat untuk pengembangan kolaboratif dan yang mungkin berpotensi terjadi dalam penelitian
mcottle
2
@Mcottle, saya pribadi lebih suka git tapi saya tidak berpikir ini adalah tempat yang tepat untuk membahas detail tentang perbedaan, terutama karena pilihannya adalah salah satu perang agama yang aktif. Lebih baik mendorong OP untuk menggunakan sesuatu daripada menakut-nakuti mereka dari daerah itu, dan keputusannya tidak permanen dalam hal apa pun.
Peter Taylor
21

Di sekolah pascasarjana, saya sendiri menulis beberapa kode algoritma-berat. Agak sulit untuk dipecahkan. Singkatnya, banyak konvensi pemrograman dibangun di sekitar gagasan memasukkan informasi ke dalam basis data, mengambilnya pada waktu yang tepat, dan kemudian memijat data itu untuk disajikan kepada pengguna, biasanya menggunakan perpustakaan untuk matematika apa pun- atau algoritma-bagian berat dari proses itu. Untuk program-program ini, semua yang pernah Anda dengar tentang OOP, memecah kode menjadi fungsi-fungsi pendek, dan membuat segala sesuatu mudah dimengerti sekilas di mana mungkin adalah saran yang sangat baik. Tapi itu tidak bekerja untuk kode algoritma-berat, atau kode yang mengimplementasikan perhitungan matematika yang kompleks dan sedikit lainnya.

Jika Anda menulis skrip untuk melakukan perhitungan ilmiah, Anda mungkin memiliki makalah dengan persamaan atau algoritma yang Anda gunakan tertulis di dalamnya. Jika Anda menggunakan ide-ide baru yang Anda temukan sendiri, mudah-mudahan Anda akan mempublikasikannya di karya Anda sendiri. Dalam kasus ini, aturannya adalah: Anda ingin kode Anda membaca sebanyak mungkin persamaan yang diterbitkan. Berikut ini adalah jawaban pada Rekayasa Perangkat Lunak. SE dengan lebih dari 200 upvotes mendukung pendekatan ini dan menjelaskan seperti apa: Apakah ada alasan untuk nama variabel pendek?

Sebagai contoh lain, ada beberapa cuplikan kode di Simbody , alat simulasi fisika yang digunakan untuk penelitian dan rekayasa fisika. Cuplikan ini memiliki komentar yang menunjukkan persamaan yang digunakan untuk perhitungan, diikuti oleh kode yang membaca sedekat mungkin dengan persamaan yang diterapkan.

ContactGeometry.cpp:

// t = (-b +/- sqrt(b^2-4ac)) / 2a
// Discriminant must be nonnegative for real surfaces
// but could be slightly negative due to numerical noise.
Real sqrtd = std::sqrt(std::max(B*B - 4*A*C, Real(0)));
Vec2 t = Vec2(sqrtd - B, -sqrtd - B) / (2*A);

ContactGeometry_Sphere.cpp:

// Solve the scalar Jacobi equation
//
//        j''(s) + K(s)*j(s) = 0 ,                                     (1)
//
// where K is the Gaussian curvature and (.)' := d(.)/ds denotes differentiation
// with respect to the arc length s. Then, j is the directional sensitivity and
// we obtain the corresponding variational vector field by multiplying b*j. For
// a sphere, K = R^(-2) and the solution of equation (1) becomes
//
//        j  = R * sin(1/R * s)                                        (2)
//          j' =     cos(1/R * s) ,                                      (3)
//
// where equation (2) is the standard solution of a non-damped oscillator. Its
// period is 2*pi*R and its amplitude is R.

// Forward directional sensitivity from P to Q
Vec2 jPQ(R*sin(k * s), cos(k * s));
geod.addDirectionalSensitivityPtoQ(jPQ);

// Backwards directional sensitivity from Q to P
Vec2 jQP(R*sin(k * (L-s)), cos(k * (L-s)));
geod.addDirectionalSensitivityQtoP(jQP);
Kevin
sumber
9
Plus satu untuk membuat "kode untuk membaca sebanyak mungkin seperti persamaan yang diterbitkan". Maaf, pendukung nama variabel yang panjang dan bermakna. Nama-nama yang paling berarti dalam kode ilmiah seringkali jahat, pendek, dan kejam justru karena itulah konvensi yang digunakan dalam makalah jurnal ilmiah yang berusaha diterapkan oleh kode tersebut. Untuk potongan kode yang menerapkan persamaan yang ditemukan dalam jurnal kertas, seringkali yang terbaik adalah tetap sedekat mungkin dengan nomenklatur di koran, dan jika ini bertentangan dengan standar standar pengkodean yang baik, sulit.
David Hammen
@ Davidvidam: Sebagai mahasiswa pascasarjana, saya menghargainya. Sebagai seorang programmer, saya kemudian akan bersikeras bahwa Anda memiliki blok komentar raksasa di bagian atas setiap fungsi yang menggambarkan dalam bahasa Inggris (atau bahasa yang Anda pilih) untuk setiap variabel, walaupun hanya pengganti sementara. Dengan begitu saya setidaknya memiliki referensi untuk melihat kembali.
tonysdg
1
@DavidHammen Selain itu, dukungan Python untuk UTF-8 dalam file sumber dan aturan sederhana untuk nama variabel membuatnya mudah untuk dideklarasikan λatau φbukan yang jelek lambda_atau phy...
Mathias Ettinger
1
@tonysdg Anda sudah memiliki referensi; itu disebut "Hammen, et al. (2018)" (atau apa pun). Ini akan menjelaskan arti dari variabel-variabel secara lebih rinci daripada blok komentar yang pernah ada. Alasan untuk menjaga nama variabel dekat dengan notasi di koran adalah untuk membuatnya lebih mudah untuk menghubungkan apa yang ada di kertas dengan apa yang ada di kode.
Tidak ada yang
17

Jadi, pekerjaan saya sehari-hari adalah dalam publikasi data penelitian dan pelestarian untuk sistem University of California. Beberapa orang telah menyebutkan reproduktifitas, dan saya pikir itu benar-benar masalah inti di sini: mendokumentasikan kode Anda seperti cara Anda mendokumentasikan apa pun yang dibutuhkan seseorang untuk mereproduksi percobaan Anda, dan, idealnya, menulis kode yang membuatnya mudah bagi orang lain. untuk mereproduksi percobaan Anda dan memeriksa hasil Anda untuk sumber kesalahan.

Tetapi sesuatu yang belum pernah saya lihat sebutkan, yang menurut saya penting, adalah bahwa lembaga pendanaan semakin melihat publikasi perangkat lunak sebagai bagian dari publikasi data, dan menjadikan publikasi perangkat lunak sebagai persyaratan untuk ilmu pengetahuan terbuka.

Untuk itu, jika Anda menginginkan sesuatu yang spesifik, ditargetkan pada peneliti daripada pengembang perangkat lunak umum, saya tidak bisa merekomendasikan organisasi Software Carpentry dengan cukup tinggi. Jika Anda dapat menghadiri salah satu bengkel mereka , bagus; jika semua yang Anda punya waktu / akses lakukan adalah membaca beberapa makalah mereka tentang praktik terbaik komputasi ilmiah , itu bagus juga. Dari yang terakhir:

Para ilmuwan biasanya mengembangkan perangkat lunak mereka sendiri untuk tujuan ini karena melakukan hal itu membutuhkan pengetahuan khusus domain yang substansial. Akibatnya, penelitian terbaru menemukan bahwa para ilmuwan biasanya menghabiskan 30% atau lebih dari waktu mereka untuk mengembangkan perangkat lunak. Namun, 90% atau lebih dari mereka adalah otodidak, dan karena itu kurang terpapar dengan praktik pengembangan perangkat lunak dasar seperti menulis kode yang dapat dipelihara, menggunakan kontrol versi dan pelacak masalah, ulasan kode, pengujian unit, dan otomatisasi tugas.

Kami percaya bahwa perangkat lunak hanyalah jenis lain dari peralatan eksperimental dan harus dibangun, diperiksa, dan digunakan dengan hati-hati seperti halnya peralatan fisik apa pun. Namun, sementara sebagian besar ilmuwan berhati-hati untuk memvalidasi peralatan laboratorium dan lapangan mereka, sebagian besar tidak tahu seberapa andal perangkat lunak mereka. Hal ini dapat menyebabkan kesalahan serius yang berdampak pada kesimpulan sentral dari penelitian yang dipublikasikan. ...

Selain itu, karena perangkat lunak sering digunakan untuk lebih dari satu proyek tunggal, dan sering digunakan kembali oleh ilmuwan lain, kesalahan komputasi dapat memiliki dampak yang tidak proporsional pada proses ilmiah. Jenis dampak berjenjang ini menyebabkan beberapa pencabutan yang menonjol ketika kesalahan dari kode kelompok lain tidak ditemukan sampai setelah publikasi.

Garis besar praktik yang mereka rekomendasikan:

  1. Tulis program untuk orang, bukan komputer
  2. Biarkan komputer melakukan pekerjaannya
  3. Buat perubahan tambahan
  4. Jangan ulangi diri Anda (atau orang lain)
  5. Rencanakan kesalahan
  6. Optimalkan perangkat lunak hanya setelah berfungsi dengan benar
  7. Desain dan tujuan dokumen, bukan mekanik
  8. Berkolaborasi

Makalah ini menjelaskan secara rinci tentang masing-masing poin ini.

David Moles
sumber
16

Apakah benar-benar masuk akal untuk menulis kode yang mengatakan OOP ketika beberapa hal standar dapat dilakukan, akan jauh lebih cepat untuk menulis, dan akan memiliki tingkat keterbacaan yang sama karena kekurangan program?

Jawaban pribadi:
Saya juga banyak menulis skrip untuk tujuan ilmiah. Untuk skrip yang lebih kecil, saya hanya mencoba mengikuti praktik pemrograman umum yang baik (yaitu menggunakan kontrol versi, mempraktikkan kontrol diri dengan nama variabel). Jika saya hanya menulis sesuatu untuk dengan cepat membuka atau memvisualisasikan dataset, saya tidak peduli dengan OOP.

Jawaban Umum:
"Tergantung." Tetapi jika Anda kesulitan untuk mencari tahu kapan harus menggunakan konsep atau paradigma pemrograman, berikut adalah beberapa hal untuk dipikirkan:

  • Skalabilitas: Apakah skrip akan berdiri sendiri, atau pada akhirnya akan digunakan dalam program yang lebih besar? Jika demikian, apakah pemrograman yang lebih besar menggunakan OOP? Bisakah kode dalam skrip Anda dengan mudah diintegrasikan ke dalam program yang lebih besar?
  • Modularitas: Secara umum, kode Anda harus modular. Namun, OOP memecah kode menjadi potongan-potongan dengan cara yang sangat istimewa. Apakah jenis modularitas itu (yaitu memecah skrip Anda menjadi kelas-kelas) masuk akal untuk apa yang Anda lakukan?

Saya ingin tahu bagaimana "memulai" dan memprogram dengan bersih proyek-proyek yang lebih kecil dan lebih cepat ini.

# 1: Biasakan diri dengan apa yang ada di luar sana:
Meskipun Anda adalah skrip "hanya" (dan Anda benar-benar hanya peduli pada komponen sains), Anda harus meluangkan waktu untuk mempelajari konsep dan paradigma pemrograman yang berbeda. Dengan begitu, Anda dapat memiliki gagasan yang lebih baik tentang apa yang harus / tidak ingin Anda gunakan dan kapan. Itu mungkin terdengar agak menakutkan. Dan Anda mungkin masih memiliki pertanyaan, "Di mana saya mulai / apa yang saya mulai cari?" Saya mencoba menjelaskan titik awal yang baik dalam dua poin berikut.

# 2: Mulailah memperbaiki apa yang Anda tahu salah:
Secara pribadi, saya akan mulai dengan hal-hal yang saya tahu salah. Dapatkan kontrol versi dan mulailah mendisiplinkan diri Anda untuk menjadi lebih baik dengan nama-nama variabel (itu adalah perjuangan yang serius). Memperbaiki apa yang Anda tahu salah mungkin terdengar jelas. Namun, dalam pengalaman saya, saya telah menemukan bahwa memperbaiki satu hal menuntun saya ke hal lain, dan seterusnya. Sebelum saya menyadarinya, saya telah mengungkap 10 hal berbeda yang saya lakukan salah dan menemukan cara untuk memperbaikinya atau bagaimana menerapkannya dengan cara yang bersih.

# 3: Dapatkan mitra pemrograman:
Jika "memulai dari awal" untuk Anda tidak melibatkan mengambil kelas formal, pertimbangkan untuk bekerja sama dengan pengembang dan meminta mereka untuk meninjau kode Anda. Bahkan jika mereka tidak memahami bagian sains dari apa yang Anda lakukan, mereka mungkin dapat memberi tahu Anda apa yang dapat Anda lakukan untuk membuat kode Anda lebih elegan.

# 4: Cari konsorsium:
Saya tidak tahu bidang ilmiah Anda. Tetapi tergantung pada apa yang Anda lakukan di dunia ilmiah, cobalah mencari konsorsium, kelompok kerja, atau peserta konferensi. Kemudian lihat apakah ada standar yang sedang mereka kerjakan. Itu dapat mengarahkan Anda ke beberapa standar pengkodean. Sebagai contoh, saya melakukan banyak pekerjaan geospasial. Melihat makalah konferensi dan kelompok kerja membawa saya ke Konsorsium Geospasial Terbuka . Salah satu yang mereka lakukan adalah mengerjakan standar untuk pengembangan geospasial.

Saya harap itu membantu!


Catatan: Saya tahu Anda baru saja menggunakan OOP sebagai contoh. Saya tidak ingin Anda berpikir bahwa saya terjebak pada bagaimana menangani penulisan kode menggunakan OOP. Lebih mudah untuk menulis jawaban yang berlanjut dengan contoh itu.

JustBlossom
sumber
Saya pikir # 3 adalah masalah yang paling penting - seorang programmer yang berpengalaman dapat memberi tahu OP konsep yang mereka butuhkan (# 1), bagaimana mengatur skrip dengan cara yang lebih baik, dan bagaimana menggunakan kontrol versi (# 2).
Doc Brown
16

Saya akan merekomendasikan untuk tetap berpegang pada prinsip Unix: Keep It Simple, Stupid! (CIUMAN)

Atau, dengan kata lain: Lakukan satu hal pada satu waktu, dan lakukan dengan baik.

Apa artinya? Pertama-tama, itu artinya fungsi Anda harus pendek. Fungsi apa pun yang tidak dapat sepenuhnya dipahami dalam tujuan, penggunaan, dan implementasi dalam beberapa detik pasti terlalu lama. Kemungkinan melakukan beberapa hal sekaligus, masing-masing harus menjadi fungsi mereka sendiri. Jadi pisahkanlah.

Dalam hal baris kode, heuristik saya adalah bahwa 10 baris adalah fungsi yang baik, dan apa pun di atas 20 kemungkinan besar omong kosong. Orang lain punya heuristik lain. Bagian penting adalah menjaga panjang ke sesuatu yang Anda dapat benar-benar pegang dalam sekejap.

Bagaimana Anda membagi fungsi yang panjang? Nah, pertama-tama Anda mencari pola kode yang berulang. Kemudian Anda faktor keluar pola-pola kode ini, beri mereka nama deskriptif, dan saksikan kode Anda menyusut . Sungguh, refactoring terbaik adalah refactoring yang mengurangi ukuran kode.

Ini terutama benar ketika fungsi yang dimaksud telah diprogram dengan salin-tempel. Setiap kali Anda melihat pola berulang seperti itu, Anda langsung tahu bahwa ini kemungkinan akan berubah menjadi fungsi tersendiri. Ini adalah prinsip Don't Repeat Yourself (DRY) . Setiap kali Anda menekan copy-paste, Anda melakukan sesuatu yang salah! Buat fungsi sebagai gantinya.

Anekdot
Saya pernah menghabiskan beberapa bulan kode refactoring yang memiliki fungsi masing-masing sekitar 500 baris. Setelah saya selesai, total kode sekitar seribu baris lebih pendek; Saya telah menghasilkan output negatif dalam hal baris kode. Saya berutang pada perusahaan ( http://www.geekherocomic.com/2008/10/09/programmers-salary-policy/index.html ). Tetap saja, saya sangat yakin bahwa ini adalah salah satu karya paling berharga yang pernah saya lakukan ...

Beberapa fungsi mungkin lama karena mereka melakukan beberapa hal berbeda satu sama lain. Ini bukan pelanggaran KERING, tetapi juga bisa dipecah. Hasilnya sering merupakan fungsi tingkat tinggi yang memanggil beberapa fungsi yang mengimplementasikan langkah-langkah individual dari fungsi aslinya. Ini umumnya akan meningkatkan ukuran kode, tetapi nama fungsi yang ditambahkan bekerja sangat baik dalam membuat kode lebih mudah dibaca. Karena sekarang Anda memiliki fungsi tingkat atas dengan semua langkahnya yang dinamai secara eksplisit. Juga, setelah pemisahan ini jelas, langkah mana yang beroperasi pada data mana. (Argumen fungsi. Anda tidak menggunakan variabel global, bukan?)

Heuristik yang baik untuk pemisahan fungsi jenis ini adalah kapan pun Anda tergoda untuk menulis komentar bagian, atau ketika Anda menemukan komentar bagian dalam kode Anda. Ini kemungkinan besar salah satu poin di mana fungsi Anda harus dipecah. Komentar bagian juga dapat berfungsi untuk menginspirasi nama untuk fungsi baru.

Prinsip KISS dan KERING dapat membawa Anda jauh. Anda tidak perlu memulai dengan OOP dll segera, seringkali Anda dapat mencapai penyederhanaan yang hebat dengan hanya menerapkan keduanya. Namun, dalam jangka panjang hasilnya akan baik untuk mengetahui tentang OOP dan paradigma lain karena mereka memberi Anda alat tambahan yang dapat Anda gunakan untuk membuat kode program Anda lebih jelas.

Akhirnya, catat setiap tindakan dengan komit. Anda memfaktorkan sesuatu ke dalam fungsi baru, itu adalah sebuah komit . Anda menggabungkan dua fungsi menjadi satu, karena mereka benar-benar melakukan hal yang sama, itu adalah sebuah komit . Jika Anda mengganti nama variabel, itu adalah sebuah komit . Berkomitmen sering. Jika satu hari berlalu, dan Anda tidak berkomitmen, Anda mungkin melakukan sesuatu yang salah.

cmaster
sumber
2
Poin bagus tentang pemisahan metode panjang. Heuristik lain yang baik mengenai paragraf pertama setelah anekdot: jika metode Anda dapat secara logis dibagi menjadi beberapa bagian dan Anda tergoda untuk menulis komentar yang menjelaskan apa yang dilakukan setiap bagian, maka itu harus dipisah pada komentar. Berita bagus, komentar-komentar itu mungkin memberi Anda ide bagus tentang apa yang disebut metode baru.
Jaquez
@ Jaquez Ah, benar-benar lupa tentang itu. Terima kasih sudah mengingatkan saya. Saya telah memperbarui jawaban saya untuk memasukkan ini :-)
cmaster
1
Poin bagus, saya ingin menyederhanakan ini untuk mengatakan bahwa "KERING" adalah faktor tunggal yang paling penting. Mengidentifikasi "pengulangan" dan menghapusnya adalah landasan dari hampir semua konstruksi pemrograman lainnya. Dengan kata lain, semua konstruksi pemrograman ada di sana, setidaknya sebagian, untuk membantu Anda membuat kode KERING. Mulailah dengan mengatakan "Tidak Ada Duplikasi Pernah" dan kemudian berlatih mengidentifikasi dan menghilangkannya. Menjadi sangat terbuka untuk apa yang mungkin merupakan duplikat - bahkan jika itu bukan kode yang mirip itu mungkin fungsi duplikat ...
Bill K
11

Saya setuju dengan yang lain bahwa kontrol versi akan menyelesaikan banyak masalah Anda segera. Secara khusus:

  • Tidak perlu menyimpan daftar perubahan apa yang telah dibuat, atau memiliki banyak salinan file, dll. Karena itulah yang dilakukan kontrol versi.
  • Tidak ada lagi file yang hilang karena ditimpa, dll. (Selama Anda tetap berpegang pada dasar-dasar; mis. Hindari "penulisan ulang riwayat")
  • Tidak perlu komentar usang, kode mati, dll disimpan di sekitar "untuk berjaga-jaga"; begitu mereka berkomitmen untuk kontrol versi, jangan ragu untuk mengabaikannya. Ini bisa terasa sangat membebaskan!

Saya akan mengatakan jangan terlalu memikirkannya: gunakan saja git. Tetap berpegang pada perintah sederhana (misalnya hanya satu mastercabang), mungkin menggunakan GUI, dan Anda harus baik-baik saja. Sebagai bonus, Anda dapat menggunakan gitlab, github, dll. Untuk penerbitan dan pencadangan gratis;)

Alasan saya menulis jawaban ini adalah untuk membahas dua hal yang mungkin Anda coba yang belum saya lihat di atas. Yang pertama adalah menggunakan pernyataan sebagai alternatif yang ringan untuk pengujian unit. Tes unit cenderung duduk "di luar" fungsi / modul / apa pun yang sedang diuji: mereka biasanya mengirim beberapa data ke dalam suatu fungsi, menerima hasil kembali, kemudian memeriksa beberapa properti hasil itu. Ini umumnya ide yang baik, tetapi mungkin tidak nyaman (terutama untuk kode "buang") karena beberapa alasan:

  • Tes unit perlu memutuskan data apa yang akan mereka berikan ke fungsi. Data itu harus realistis (jika tidak ada gunanya mengujinya), ia harus memiliki format yang benar, dll.
  • Tes unit harus memiliki "akses" ke hal-hal yang ingin mereka nyatakan. Secara khusus, tes unit tidak dapat memeriksa data antara apa pun di dalam suatu fungsi; kita harus memecah fungsi itu menjadi potongan-potongan kecil, menguji potongan-potongan itu, dan menyambungkannya di tempat lain.
  • Tes unit juga dianggap relevan dengan program. Misalnya, test suites dapat menjadi "basi" jika ada perubahan besar sejak terakhir kali dijalankan, dan bahkan mungkin ada banyak tes untuk kode yang bahkan tidak digunakan lagi.

Pernyataan tidak memiliki kelemahan ini, karena mereka diperiksa selama eksekusi normal suatu program. Khususnya:

  • Karena dijalankan sebagai bagian dari eksekusi program normal, kami memiliki data dunia nyata yang sebenarnya untuk dimainkan. Ini tidak memerlukan kurasi terpisah dan (menurut definisi) realistis dan memiliki format yang benar.
  • Pernyataan dapat ditulis di mana saja dalam kode, sehingga kami dapat menempatkannya di mana pun kami memiliki akses ke data yang ingin kami periksa. Jika kita ingin menguji beberapa nilai menengah dalam suatu fungsi, kita bisa menaruh beberapa pernyataan di tengah fungsi itu!
  • Karena mereka ditulis in-line, pernyataan tidak dapat "tidak sinkron" dengan struktur kode. Jika kami memastikan bahwa asersi dicentang secara default, kami juga tidak perlu khawatir mereka menjadi "basi" karena kami akan segera melihat apakah mereka lulus atau tidak pada saat kami menjalankan program berikutnya!

Anda menyebutkan kecepatan sebagai faktor, dalam hal ini pemeriksaan pernyataan mungkin tidak diinginkan dalam loop itu (tetapi masih berguna untuk memeriksa pengaturan dan pemrosesan selanjutnya). Namun, hampir semua implementasi asersi menyediakan cara untuk mematikannya; misalnya dengan Python mereka tampaknya dapat dinonaktifkan dengan menjalankan dengan -Oopsi (saya tidak tahu ini, karena saya tidak pernah merasa perlu untuk menonaktifkan salah satu dari pernyataan saya sebelumnya). Saya akan merekomendasikan bahwa Anda meninggalkan mereka disecara default; jika siklus pengodean / debugging / pengujian Anda melambat, Anda mungkin lebih baik melakukan pengujian dengan subset data yang lebih kecil, atau melakukan lebih sedikit iterasi dari beberapa simulasi selama pengujian, atau apa pun. Jika Anda benar-benar menonaktifkan pernyataan dalam pengujian non-berjalan karena alasan kinerja, hal pertama yang saya sarankan Anda lakukan adalah mengukur apakah mereka sebenarnya sumber perlambatan! (Sangat mudah untuk menipu diri kita sendiri ketika datang ke kemacetan kinerja)

Saran terakhir saya adalah menggunakan sistem build yang mengelola dependensi Anda. Saya pribadi menggunakan Nix untuk ini, tetapi telah mendengar hal-hal baik tentang Guix juga. Ada juga alternatif seperti Docker, yang jauh kurang berguna dari perspektif ilmiah tetapi mungkin sedikit lebih akrab.

Sistem seperti Nix baru-baru ini menjadi (sedikit) populer, dan beberapa orang mungkin menganggapnya berlebihan untuk "membuang" kode seperti yang Anda jelaskan, tetapi manfaatnya untuk reproduksibilitas komputasi ilmiah sangat besar. Pertimbangkan skrip shell untuk menjalankan percobaan, seperti ini (misalnya run.sh):

#!/usr/bin/env bash
set -e
make all
./analyse < ./dataset > output.csv

Kami dapat menulis ulangnya menjadi "derivasi" Nix, seperti ini (misalnya run.nix):

with import <nixpkgs> {};
runCommand "output.csv" {} ''
  cp -a ${./.} src
  cd src
  make all
  ./analyse < ./dataset > $out
''

Hal-hal di antaranya ''...''adalah kode bash, sama seperti yang kami miliki sebelumnya, kecuali yang ${...}dapat digunakan untuk "splice" dalam konten string lain (dalam hal ini ./., yang akan diperluas ke jalur direktori yang berisi run.nix). The with import ...garis mengimpor Nix ini perpustakaan standar , yang menyediakan runCommanduntuk menjalankan kode bash. Kita dapat menjalankan eksperimen menggunakan nix-build run.nix, yang akan memberikan jalan seperti /nix/store/1wv437qdjg6j171gjanj5fvg5kxc828p-output.csv.

Jadi, apa ini membeli kita? Nix akan secara otomatis mengatur lingkungan "bersih", yang hanya memiliki akses ke hal-hal yang telah kami minta secara eksplisit. Secara khusus ia tidak memiliki akses ke variabel seperti $HOMEatau perangkat lunak sistem apa pun yang telah kami instal. Ini menjadikan hasil independen dari detail mesin kami saat ini, seperti konten ~/.configatau versi program yang kami instal; AKA hal-hal yang mencegah orang lain meniru hasil kami! Ini sebabnya saya menambahkan itucpperintah, karena proyek tidak akan dapat diakses secara default. Mungkin tampak menjengkelkan bahwa perangkat lunak sistem tidak tersedia untuk skrip Nix, tetapi sebaliknya juga: kita tidak memerlukan apa pun yang diinstal pada sistem kami (selain Nix) untuk memanfaatkannya dalam skrip; kami hanya memintanya dan Nix akan keluar dan mengambil / mengkompilasi / apa pun yang diperlukan (kebanyakan hal akan diunduh sebagai binari; perpustakaan standar juga sangat besar!). Misalnya, jika kita menginginkan banyak paket Python dan Haskell tertentu, untuk beberapa versi tertentu dari bahasa-bahasa tersebut, ditambah beberapa sampah lainnya (karena mengapa tidak?):

with import <nixpkgs> {};
runCommand "output.csv"
  {
    buildInputs = [
      gcc49 libjson zlib
      haskell.packages.ghc802.pandoc
      (python34.withPackages (pyPkgs: [
        pyPkgs.beautifulsoup4 pyPkgs.numpy pyPkgs.scipy
        pyPkgs.tensorflowWithoutCuda
      ]))
    ];
  }
  ''
    cp -a ${./.} src
    cd src
    make all
    ./analyse < ./dataset > $out
  ''

Hal yang sama nix-build run.nixakan menjalankan ini, mengambil semua yang kami minta terlebih dahulu (dan menyimpannya semua kalau-kalau kami menginginkannya nanti). Output (semua file / direktori yang dipanggil $out) akan disimpan oleh Nix, yang merupakan jalan yang diludahkan. Itu diidentifikasi oleh hash kriptografi dari semua input yang kami minta (isi skrip, paket lain, nama, flag kompiler, dll.); paket-paket lain diidentifikasi oleh hash input mereka , dan seterusnya sehingga kami memiliki rantai penuh keunggulan untuk semuanya, segera kembali ke versi GCC yang menyusun versi GCC yang menyusun bash, dan seterusnya!

Mudah-mudahan saya telah menunjukkan bahwa ini banyak membeli kita untuk kode ilmiah, dan cukup mudah untuk memulai. Ini juga mulai dianggap sangat serius oleh para ilmuwan, misalnya (hit Google teratas) https://dl.acm.org/citation.cfm?id=2830172 jadi mungkin keterampilan yang berharga untuk dikembangkan (seperti pemrograman)

Warbo
sumber
2
Jawaban berguna yang sangat terperinci - Saya benar-benar menyukai jawaban yang lain, tetapi pernyataan itu terdengar seperti langkah pertama yang sangat berguna.
heather
9

Tanpa pergi ke kontrol versi lengkap + pengemasan + unit tes jenis pola pikir (yang merupakan praktik pemrograman yang baik yang harus Anda coba capai di beberapa titik), salah satu solusi menengah yang saya pikir akan cocok adalah dengan menggunakan Jupiter Notebook . Ini tampaknya lebih baik diintegrasikan dengan perhitungan ilmiah.

Ini memiliki keuntungan bahwa Anda dapat mencampur pikiran Anda dengan kode; menjelaskan mengapa suatu pendekatan lebih baik daripada yang lain dan meninggalkan kode lama apa adanya di bagian ad-hoc. Selain menggunakan sel dengan benar akan secara alami membawa Anda untuk memecah kode Anda dan mengaturnya menjadi fungsi yang dapat membantu pemahamannya.

Mathias Ettinger
sumber
1
Plus ini sangat membantu dengan reproduksibilitas - Anda dapat menjalankan kode yang persis sama untuk menghasilkan angka publikasi misalnya, atau untuk kembali ke sesuatu yang Anda simpan beberapa bulan yang lalu mungkin untuk memasukkan komentar resensi.
afaulconbridge
Untuk seseorang yang ingin membaca lebih lanjut, ini juga dikenal sebagai pemrograman melek.
llrs
6

Jawaban teratas sudah baik, tetapi saya ingin menjawab beberapa pertanyaan Anda secara langsung.

Apakah pengujian unit diperlukan untuk menulis potongan kode yang lebih kecil?

Ukuran kode tidak secara langsung berkaitan dengan kebutuhan untuk tes unit. Ini terkait secara tidak langsung: tes unit lebih berharga dalam basis kode kompleks , dan basis kode kecil umumnya tidak serumit yang lebih besar.

Tes unit bersinar untuk kode di mana mudah untuk membuat kesalahan, atau ketika Anda akan memiliki banyak implementasi kode ini. Tes unit tidak banyak membantu Anda dengan perkembangan saat ini , tetapi mereka melakukan banyak hal untuk mencegah Anda membuat kesalahan di masa depan yang menyebabkan kode yang ada tiba-tiba bertingkah buruk (walaupun Anda tidak menyentuh hal itu).

Katakanlah Anda memiliki aplikasi di mana Perpustakaan A melakukan kuadrat angka, dan Perpustakaan B menerapkan teorema Pythagoras. Jelas, B tergantung pada A. Anda perlu memperbaiki sesuatu di perpustakaan A, dan katakanlah Anda memperkenalkan bug yang kubus angka daripada mengkuadratkannya.

Perpustakaan B tiba-tiba akan mulai berperilaku buruk, mungkin melemparkan pengecualian atau hanya memberikan output yang salah. Dan ketika Anda melihat sejarah versi perpustakaan B, Anda melihat bahwa itu tidak tersentuh. Hasil akhir yang bermasalah adalah bahwa Anda tidak memiliki indikasi apa yang mungkin salah, dan Anda harus men-debug perilaku B sebelum Anda menyadari masalahnya ada di A. Itu adalah usaha yang sia-sia.

Masukkan tes unit. Tes ini mengkonfirmasi bahwa perpustakaan A berfungsi sebagaimana mestinya. Jika Anda memperkenalkan bug di perpustakaan A yang menyebabkannya mengembalikan hasil yang buruk, maka pengujian unit Anda akan menangkapnya. Oleh karena itu, Anda tidak akan terjebak mencoba men-debug pustaka B.
Ini di luar jangkauan Anda, tetapi dalam pengembangan integrasi berkelanjutan, pengujian unit dijalankan setiap kali seseorang melakukan beberapa kode, yang berarti Anda akan tahu Anda telah memecahkan sesuatu ASAP.

Khusus untuk operasi matematika yang rumit, unit test dapat menjadi berkah. Anda melakukan beberapa contoh perhitungan, dan kemudian Anda menulis unit test yang membandingkan output terhitung dan output aktual Anda (berdasarkan parameter input yang sama).

Namun, perhatikan bahwa tes unit tidak akan membantu Anda membuat kode yang baik, tetapi mempertahankannya . Jika Anda biasanya menulis kode sekali dan tidak pernah mengunjungi lagi, tes unit akan kurang bermanfaat.

Bagaimana dengan OOP?

OOP adalah cara berpikir tentang entitas yang berbeda, misalnya:

Ketika seorang Customeringin membeli Product, ia berbicara kepada Vendoruntuk menerima Order. Kemudian Accountantakan membayar Vendor.

Bandingkan ini dengan cara seorang programmer fungsional memikirkan hal-hal:

Ketika seorang pelanggan ingin purchaseProduct(), dia talktoVendor()jadi mereka akan sendOrder()kepadanya. Penghitung akan melakukannya payVendor().

Apel dan jeruk. Tak satu pun dari mereka secara obyektif lebih baik dari yang lain. Satu hal yang menarik untuk dicatat adalah bahwa untuk OOP, Vendordisebutkan dua kali tetapi mengacu pada hal yang sama. Namun, untuk pemrograman fungsional, talktoVendor()dan payVendor()dua hal terpisah.
Ini menunjukkan perbedaan antara pendekatan. Jika ada banyak logika khusus vendor bersama antara kedua tindakan ini, maka OOP membantu mengurangi duplikasi kode. Namun, jika tidak ada logika bersama antara keduanya, maka menggabungkan mereka menjadi satu Vendoradalah pekerjaan yang sia-sia (dan karena itu pemrograman fungsional lebih efisien).

Lebih sering daripada tidak, perhitungan matematika dan ilmiah adalah operasi yang berbeda yang tidak bergantung pada logika / rumus bersama implisit. Karena itu, pemrograman fungsional lebih sering digunakan daripada OOP.

Apa jenis pendekatan yang baik untuk menulis kode yang baik dan bersih dengan cepat ketika melakukan "pemrograman ilmiah" sebagai lawan bekerja pada proyek yang lebih besar?

Pertanyaan Anda menyiratkan bahwa definisi "kode yang baik, bersih" berubah apakah Anda melakukan pemrograman ilmiah atau bekerja pada proyek yang lebih besar (saya asumsikan Anda maksud perusahaan).

Definisi kode yang baik tidak berubah. Namun, kebutuhan untuk menghindari kerumitan (yang bisa dilakukan dengan menulis kode bersih) memang berubah.

Argumen yang sama kembali ke sini.

  • Jika Anda tidak pernah meninjau kembali kode lama dan sepenuhnya memahami logika tanpa perlu memisah-misahkannya, maka jangan menghabiskan upaya yang berlebihan untuk membuat hal-hal dapat dipertahankan.
  • Jika Anda mengunjungi kembali kode lama, atau logika yang diperlukan terlalu rumit bagi Anda untuk menangani semuanya sekaligus (sehingga mengharuskan Anda untuk mengelompokkan solusi), maka fokuslah pada penulisan yang bersih, tutup yang dapat digunakan kembali.

Saya mengajukan pertanyaan ini karena seringkali, pemrograman itu sendiri tidak super kompleks. Ini lebih tentang matematika atau sains yang saya uji atau teliti dengan pemrograman.

Saya mendapatkan perbedaan yang Anda buat di sini, tetapi ketika Anda melihat kembali kode yang ada, Anda melihat matematika dan pemrogramannya. Jika salah dibuat atau rumit, maka Anda akan kesulitan untuk membacanya.

Misalnya, apakah kelas diperlukan ketika dua variabel dan suatu fungsi mungkin bisa mengatasinya?

Selain prinsip OOP, alasan utama saya menulis kelas untuk menampung beberapa nilai data adalah karena menyederhanakan menyatakan parameter metode dan mengembalikan nilai. Sebagai contoh, jika saya memiliki banyak metode yang menggunakan lokasi (lat / lon pair), maka saya akan cepat bosan karena harus mengetik float latitude, float longitudedan akan lebih suka menulis Location loc.

Ini diperparah lebih lanjut ketika Anda mempertimbangkan bahwa metode umumnya mengembalikan satu nilai (kecuali fitur spesifik bahasa ada untuk mengembalikan lebih banyak nilai), dan hal-hal seperti lokasi ingin Anda mengembalikan dua nilai (lat + lon). Ini memberi Anda insentif untuk membuat Locationkelas untuk menyederhanakan kode Anda.

Misalnya, apakah kelas diperlukan ketika dua variabel dan suatu fungsi mungkin bisa mengatasinya?

Hal lain yang menarik untuk dicatat adalah Anda dapat menggunakan OOP tanpa mencampurkan nilai dan metode data. Tidak semua pengembang setuju di sini (beberapa menyebutnya sebagai antipattern), tetapi Anda dapat memiliki model data anemia di mana Anda memiliki kelas data terpisah (menyimpan bidang nilai) dan kelas logika (menyimpan metode).
Ini, tentu saja, pada spektrum. Anda tidak perlu menderita anemia sempurna, Anda dapat menggunakannya saat Anda menganggapnya tepat.

Sebagai contoh, metode yang hanya menggabungkan nama depan dan belakang seseorang masih dapat ditempatkan di Personkelas itu sendiri, karena itu bukan benar-benar "logika" melainkan nilai yang dihitung.

(Pertimbangkan ini juga umumnya situasi di mana kecepatan program lebih disukai berada di ujung yang lebih cepat - ketika Anda menjalankan 25.000.000 langkah waktu simulasi, Anda agak menginginkannya.)

Kelas selalu sebesar jumlah bidangnya. Mengambil contoh Locationlagi, yang terdiri dari dua floatnilai, penting untuk dicatat di sini bahwa satu Locationobjek akan mengambil memori sebanyak dua floatnilai yang terpisah .

Dalam hal itu, tidak masalah apakah Anda menggunakan OOP atau tidak. Jejak memori sama.

Performa itu sendiri juga bukan halangan besar untuk dilewati. Perbedaan antara misalnya menggunakan metode global atau metode kelas tidak ada hubungannya dengan kinerja runtime, tetapi semuanya terkait dengan pembuatan bytecode waktu kompilasi.

Pikirkan seperti ini: apakah saya menulis resep kue saya dalam bahasa Inggris atau Spanyol tidak mengubah fakta bahwa kue akan memakan waktu 30 menit untuk dipanggang (= kinerja runtime). Satu-satunya hal yang diubah bahasa resep adalah bagaimana si juru masak mencampurkan bahan-bahannya (= mengkompilasi bytecode).

Khususnya untuk Python, Anda tidak perlu mengkompilasi kode secara eksplisit sebelum memanggilnya. Namun, ketika Anda tidak melakukan pra-kompilasi, kompilasi akan terjadi ketika mencoba mengeksekusi kode. Ketika saya mengatakan "runtime", maksud saya eksekusi itu sendiri, bukan kompilasi yang bisa mendahului eksekusi.

Flater
sumber
6

Manfaat kode ilmiah bersih

  • ... melihat buku-buku pemrograman, mereka sering tampaknya ditujukan pada proyek yang lebih besar.

  • ... apakah benar-benar masuk akal untuk menulis kode yang mengatakan OOP ketika beberapa hal standar dapat dilakukan, akan jauh lebih cepat untuk menulis, dan akan memiliki tingkat keterbacaan yang sama karena kekurangan program?

Mungkin bermanfaat untuk mempertimbangkan kode Anda dari perspektif pembuat kode masa depan.

  • Mengapa mereka membuka file ini?
  • Apa yang mereka cari?

Dari pengalaman saya,

Kode bersih harus memudahkan verifikasi hasil Anda

  • Permudah pengguna untuk tahu persis apa yang harus mereka lakukan untuk menjalankan program Anda.
  • Anda mungkin ingin membagi program Anda sehingga masing-masing algoritma dapat dibandingkan secara terpisah.

  • Hindari menulis fungsi dengan efek samping kontra-intuitif di mana satu operasi yang tidak terkait menyebabkan operasi lain berperilaku berbeda. Jika Anda tidak dapat menghindarinya, dokumentasikan apa yang dibutuhkan kode Anda dan cara mengaturnya.

Kode bersih dapat berfungsi sebagai kode contoh untuk coders masa depan

Komentar yang jelas (termasuk yang menunjukkan bagaimana fungsi harus dipanggil) dan fungsi yang terpisah dapat membuat perbedaan besar dalam berapa lama bagi seseorang yang baru memulai (atau masa depan Anda) untuk membuat sesuatu yang berguna dari pekerjaan Anda.

Selain itu, membuat "API" nyata untuk algoritme Anda dapat membuat Anda lebih siap jika Anda memutuskan untuk membuat skrip Anda menjadi perpustakaan nyata untuk digunakan orang lain.

Rekomendasi

"Kutip" rumus matematika menggunakan komentar.

  • Tambahkan komentar ke rumus matematika "kutip", terutama jika Anda menggunakan optimisasi (identitas trigonometri, seri Taylor, dll).
  • Jika Anda mendapatkan formula dari buku, tambahkan komentar yang mengatakan John Smith Method from Some Book 1st Ed. Section 1.2.3 Pg 180, jika Anda menemukan formula di situs web atau di kertas, kutip juga.
  • Saya sarankan untuk menghindari komentar "hanya tautan", pastikan Anda merujuk pada metode dengan nama di suatu tempat untuk memungkinkan orang untuk google, saya telah mengalami beberapa komentar "hanya tautan" yang diarahkan ke halaman internal lama dan mereka bisa sangat membuat frustasi .
  • Anda dapat mencoba mengetik rumus dalam komentar Anda jika masih mudah dibaca di Unicode / ASCII, tetapi ini bisa menjadi sangat canggung (komentar kode bukan LaTeX).

Gunakan komentar dengan bijak

Jika Anda dapat meningkatkan keterbacaan kode Anda dengan menggunakan nama variabel / nama fungsi yang baik, lakukan itu terlebih dahulu. Ingatlah bahwa komentar akan bertahan selamanya sampai Anda menghapusnya, jadi cobalah untuk membuat komentar yang tidak akan kedaluwarsa.

Gunakan nama variabel deskriptif

  • Variabel huruf tunggal mungkin menjadi pilihan terbaik jika mereka merupakan bagian dari formula.
  • Mungkin penting bagi pembaca di masa depan untuk dapat melihat kode yang Anda tulis dan membandingkannya dengan persamaan yang Anda terapkan.
  • Jika perlu, pertimbangkan untuk menambahkan akhiran untuk menjelaskan arti sebenarnya, misalnya,. xBar_AverageVelocity
  • Seperti yang disebutkan sebelumnya, saya sarankan dengan jelas menunjukkan formula / metode yang Anda gunakan dengan nama di komentar di suatu tempat.

Tulis kode untuk menjalankan program Anda terhadap data buruk yang diketahui baik dan buruk.

Apakah pengujian unit diperlukan untuk menulis potongan kode yang lebih kecil?

Saya pikir pengujian unit dapat membantu, saya pikir bentuk terbaik pengujian unit untuk kode ilmiah adalah serangkaian tes yang dijalankan pada data yang diketahui buruk dan baik.

Tulis beberapa kode untuk menjalankan algoritme Anda dan periksa untuk melihat seberapa jauh hasilnya menyimpang dari yang Anda harapkan. Ini akan membantu Anda menemukan masalah (berpotensi sangat buruk dan sulit ditemukan) di mana Anda secara tidak sengaja membuat kode sesuatu yang menyebabkan hasil positif palsu, atau membuat kesalahan yang menyebabkan fungsi selalu mengembalikan nilai yang sama.

Perhatikan bahwa ini dapat dilakukan pada tingkat abstraksi apa pun. Misalnya, Anda dapat menguji keseluruhan algoritma pencocokan pola, atau Anda dapat menguji fungsi yang hanya menghitung jarak antara dua hasil dalam proses optimasi Anda. Mulailah dengan bidang yang paling penting untuk hasil Anda terlebih dahulu, dan / atau bagian-bagian kode yang paling Anda khawatirkan.

Buat lebih mudah untuk menambahkan kasus uji baru, pertimbangkan untuk menambahkan fungsi "pembantu", dan susun data input Anda secara efektif. Ini mungkin berarti menyimpan data input ke file sehingga Anda dapat dengan mudah menjalankan kembali tes, meskipun sangat berhati-hati untuk menghindari positif palsu atau kasus tes yang bias / sepele diselesaikan.

Pertimbangkan untuk menggunakan sesuatu seperti validasi silang , lihat posting ini di cross divalidasi untuk informasi lebih lanjut.

Gunakan kontrol versi

Saya akan merekomendasikan menggunakan kontrol versi dan hosting repositori Anda di situs eksternal. Ada situs yang akan meng-host repositori secara gratis.

Keuntungan:

  1. Ini memberikan cadangan jika hard disk Anda gagal
  2. Ini memberikan sejarah, yang membuat Anda tidak khawatir jika masalah baru-baru ini muncul disebabkan oleh Anda secara tidak sengaja mengubah file, di antara manfaat lainnya.
  3. Ini memungkinkan Anda untuk menggunakan percabangan, yang merupakan cara yang baik untuk bekerja pada kode jangka panjang / eksperimental tanpa memengaruhi pekerjaan yang tidak terkait.

Berhati-hatilah saat menyalin / menempelkan kode

Gaya kode saya berbelit-belit dan dipenuhi dengan komentar usang yang mencatat cara alternatif untuk melakukan sesuatu atau dengan baris kode yang disalin.

  • Menyalin / menempel kode dapat menghemat waktu Anda, tetapi ini adalah salah satu hal paling berbahaya yang dapat Anda lakukan, terutama jika itu kode yang tidak Anda tulis sendiri (misalnya, jika itu kode dari kolega).

  • Segera setelah Anda mendapatkan kode yang berfungsi dan diuji, saya akan merekomendasikan melaluinya dengan sangat hati-hati untuk mengubah nama variabel atau komentar apa pun yang Anda tidak mengerti.

jrh
sumber
6

Alat-alat perdagangan biasanya diciptakan untuk menyelesaikan suatu kebutuhan. Jika Anda perlu menggunakan alat ini, jika tidak, kemungkinan besar Anda tidak perlu melakukannya.

Secara khusus, program ilmiah bukanlah target akhir, mereka adalah sarana. Anda menulis program untuk menyelesaikan masalah yang Anda miliki sekarang - Anda tidak mengharapkan program itu digunakan oleh orang lain (dan harus dipelihara) dalam sepuluh tahun. Itu saja berarti Anda tidak perlu memikirkan alat apa pun yang memungkinkan pengembang saat ini untuk mencatat riwayat untuk orang lain seperti kontrol versi, atau menangkap fungsionalitas dalam kode seperti tes unit.

Apa yang akan menguntungkan Anda?

  • kontrol versi bagus karena memungkinkan Anda untuk dengan mudah membuat cadangan pekerjaan Anda. Pada 2018 github adalah tempat yang sangat populer untuk melakukannya (dan Anda selalu dapat memindahkannya nanti jika diperlukan - git sangat fleksibel). Pengganti cadangan yang murah dan sederhana adalah prosedur pencadangan otomatis di sistem operasi Anda (Time Machine untuk Mac, rsync untuk Linux, dll.). Kode Anda harus ada di banyak tempat!
  • Tes unit bagus karena jika Anda menulisnya terlebih dahulu, Anda dipaksa untuk berpikir tentang cara memeriksa apa kode sebenarnya, yang membantu Anda merancang API yang lebih berguna untuk kode Anda. Ini berguna jika Anda pernah masuk ke dalam penulisan kode untuk digunakan kembali nanti dan membantu Anda saat mengubah suatu algoritma karena Anda tahu itu berfungsi pada kasus-kasus ini.
  • Dokumentasi. Belajar menulis dokumentasi yang tepat dalam bahasa pemrograman yang Anda gunakan (javadoc untuk Java misalnya). Tulis untuk masa depan Anda. Dalam proses ini, Anda akan menemukan bahwa nama variabel yang baik membuat dokumentasi lebih mudah. Pengulangan. Berikan perhatian yang sama pada dokumentasi Anda seperti yang dilakukan penyair terhadap puisi.
  • Gunakan alat yang bagus. Temukan IDE yang membantu Anda dan mempelajarinya dengan baik. Refactoring seperti mengubah nama variabel menjadi nama yang lebih baik jauh lebih mudah dengan cara ini.
  • Jika Anda memiliki teman sebaya, pertimbangkan untuk menggunakan peer review. Memiliki orang luar melihat dan memahami kode Anda, adalah versi masa depan di sini dan sekarang yang Anda tulis. Jika rekan Anda tidak memahami kode Anda, Anda mungkin tidak akan melakukannya nanti.
Thorbjørn Ravn Andersen
sumber
Bagaimana jawaban ini tidak menerima upvote? Sudah sekarang. Grup kami telah menemukan peer review sebagai salah satu alat yang paling efektif dari semuanya, jauh lebih penting daripada tes unit ketika datang ke kode ilmiah. Sangat mudah untuk membuat kesalahan ketika menerjemahkan satu set persamaan kompleks dalam artikel jurnal ilmiah ke kode. Para ilmuwan dan insinyur seringkali membuat programer yang sangat buruk; peer review dapat menangkap kejelekan arsitektur yang membuat kode sulit untuk dipelihara / dipahami / digunakan.
David Hammen
5

Selain saran bagus yang sudah ada di sini, Anda mungkin ingin mempertimbangkan tujuan pemrograman Anda, dan karena itu apa yang penting bagi Anda.

"Ini lebih tentang matematika atau sains yang saya uji atau teliti dengan pemrogramannya."

Jika tujuannya adalah untuk bereksperimen dan menguji sesuatu untuk pemahaman Anda sendiri dan Anda tahu apa hasilnya seharusnya maka kode Anda pada dasarnya adalah membuang-cepat dan pendekatan Anda saat ini mungkin sudah cukup, meskipun dapat ditingkatkan. Jika hasilnya tidak seperti yang diharapkan, Anda dapat kembali dan meninjau.

Namun, jika hasil coding Anda menginformasikan arah penelitian Anda dan Anda tidak tahu apa hasilnya harus menjadi, maka kebenaran menjadi sangat penting. Kesalahan dalam kode Anda dapat menyebabkan Anda menarik kesimpulan yang salah dari eksperimen Anda dengan berbagai implikasi buruk bagi keseluruhan riset Anda.

Dalam hal ini, memecah kode Anda menjadi fungsi yang mudah dimengerti dan diverifikasi dengan unit test akan memberi Anda batu bata bangunan yang lebih solid memberi Anda lebih percaya diri pada hasil Anda dan dapat menyelamatkan Anda dari banyak frustrasi nanti.

Aidan
sumber
5

Sama bagusnya dengan kontrol versi dan pengujian unit untuk menjaga kode keseluruhan Anda terorganisir dan fungsional, tidak ada yang benar-benar membantu Anda menulis kode yang lebih bersih.

  • Kontrol versi akan memungkinkan Anda untuk melihat bagaimana dan kapan kode menjadi berantakan seperti itu.
  • Tes unit akan memastikan bahwa, meskipun kode menjadi berantakan, masih berfungsi.

Jika Anda ingin menghentikan diri Anda dari menulis kode yang berantakan, Anda memerlukan alat yang berfungsi di mana kekacauan terjadi: ketika Anda menulis kode. Jenis alat yang populer disebut linter. Saya bukan pengembang python, tetapi sepertinya Pylint mungkin merupakan pilihan yang baik.

Linter melihat kode yang telah Anda tulis, dan membandingkannya dengan seperangkat praktik terbaik yang dapat dikonfigurasi. Jika linter memiliki aturan bahwa variabel harus camelCase, dan Anda menuliskannya snake_case, itu akan menandai itu sebagai kesalahan. Linter yang baik memiliki aturan mulai dari "variabel yang dideklarasikan harus digunakan" hingga "Kompleksitas fungsi siklomatik harus kurang dari 3".

Sebagian besar editor kode dapat dikonfigurasikan untuk menjalankan linter setiap kali Anda menyimpan, atau hanya secara umum saat Anda mengetik, dan menunjukkan masalah sebaris. Jika Anda mengetikkan sesuatu seperti x = 7, xakan disorot, dengan instruksi untuk menggunakan nama yang lebih panjang dan lebih baik (jika itu yang Anda konfigurasikan). Ini berfungsi seperti periksa ejaan pada sebagian besar pengolah kata, membuatnya sulit untuk diabaikan, dan membantu membangun kebiasaan yang lebih baik.

Mike Gossmann
sumber
Ini seharusnya memiliki lebih banyak upvotes. +1
heather
2
Tapi, demi Tuhan, pastikan bahwa Anda tahu cara mengkonfigurasi linter ke gaya yang Anda suka, jika tidak, itu akan membuat Anda marah dengan keributannya.
DrMcCleod
4

Semua yang Anda daftarkan adalah alat di kotak alat metaforis. Seperti apa pun dalam hidup, alat yang berbeda sesuai untuk tugas yang berbeda.

Dibandingkan dengan bidang teknik lainnya, perangkat lunak bekerja dengan banyak potongan individual yang cukup sederhana. Pernyataan tugas tidak dievaluasi secara berbeda tergantung pada fluktuasi suhu ruangan. Sebuah ifpernyataan tidak menimbulkan korosi dan terus mengembalikan hal yang sama setelah beberapa saat. Tetapi karena unsur-unsur individu sangat sederhana, dan perangkat lunak yang dibuat oleh manusia, unsur-unsur tersebut digabungkan menjadi potongan-potongan yang lebih besar dan lebih besar sampai hasilnya menjadi begitu besar dan kompleks sehingga mencapai batas apa yang dapat dikelola orang secara mental.

Sebagai proyek perangkat lunak telah tumbuh dan berkembang, orang telah mempelajarinya dan menciptakan alat untuk mencoba mengelola kompleksitas itu. OOP adalah salah satu contohnya. Semakin banyak bahasa pemrograman abstrak adalah cara lain. Karena sebagian besar uang dalam perangkat lunak melakukan lebih banyak lagi , alat untuk mencapai itulah yang akan Anda lihat dan baca. Tapi sepertinya situasi itu tidak berlaku untuk Anda.

Jadi, jangan merasa Anda perlu melakukan semua itu. Pada akhirnya, kode itu hanyalah alat untuk mencapai tujuan. Sayangnya, apa yang terbaik memberi Anda perspektif yang tepat tentang apa yang ada dan apa yang tidak sesuai adalah bekerja pada beberapa proyek yang lebih besar, karena jauh lebih sulit untuk mengetahui apa yang hilang ketika kotak peralatan itu ada di pikiran Anda.

Bagaimanapun, saya tidak akan khawatir tentang tidak menggunakan OOP atau teknik lain selama skrip Anda kecil. Banyak masalah yang Anda uraikan hanyalah keterampilan organisasi profesional umum, yaitu tidak kehilangan file lama adalah sesuatu yang harus dihadapi semua bidang.

Apa namanya
sumber
4

Selain semua saran bagus yang diberikan sejauh ini, satu praktik yang saya pelajari dari waktu ke waktu dan penting adalah dengan sangat bebas menambahkan komentar terperinci ke kode Anda. Ini adalah satu-satunya hal terpenting bagi saya ketika saya kembali ke sesuatu setelah selang waktu yang lama. Jelaskan pada diri sendiri apa yang Anda pikirkan. Dibutuhkan sedikit waktu untuk melakukannya tetapi relatif mudah dan kebanyakan tidak menyakitkan.

Saya kadang-kadang memiliki dua atau tiga kali lebih banyak baris komentar daripada kode, terutama ketika konsep atau tekniknya baru bagi saya dan saya harus menjelaskan kepada diri sendiri.

Lakukan kontrol versi, perbaiki praktik Anda, dll .... semua hal di atas. Tetapi jelaskan hal-hal untuk diri Anda saat Anda pergi. Ini bekerja dengan sangat baik.

Bob Newell
sumber
4

Kualitas apa yang penting untuk program semacam ini?

Mungkin tidak masalah apakah itu mudah untuk mempertahankan atau mengembangkannya, karena kemungkinan itu tidak akan terjadi.

Mungkin tidak masalah seberapa efisien itu.

Mungkin tidak masalah apakah itu memiliki antarmuka pengguna yang hebat atau apakah itu aman terhadap penyerang jahat.

Mungkin penting bahwa itu dapat dibaca: bahwa seseorang yang membaca kode Anda dapat dengan mudah meyakinkan diri sendiri bahwa itu melakukan apa yang diklaimnya lakukan.

Itu tentu penting bahwa itu benar. Jika program memberikan hasil yang salah, itu kesimpulan ilmiah Anda di luar jendela. Tetapi hanya perlu memproses dengan benar input yang sebenarnya Anda minta untuk diproses; itu benar-benar tidak terlalu penting apakah itu jatuh jika diberi nilai data input negatif, jika semua nilai data Anda positif.

Penting juga bagi Anda untuk mempertahankan beberapa level kontrol perubahan. Hasil ilmiah Anda harus dapat direproduksi, dan itu berarti Anda perlu tahu versi program mana yang menghasilkan hasil yang ingin Anda publikasikan. Karena hanya ada satu pengembang, kontrol perubahan tidak perlu terlalu rumit, tetapi Anda perlu memastikan bahwa Anda dapat kembali ke titik waktu dan mereproduksi hasil Anda.

Jadi jangan khawatir tentang paradigma pemrograman, orientasi objek, keanggunan algoritmik. Jangan khawatir tentang kejelasan dan keterbacaan dan tentang keterlacakan perubahan Anda dari waktu ke waktu. Jangan khawatir tentang antarmuka pengguna. Jangan khawatir tentang pengujian setiap kemungkinan kombinasi parameter input, tetapi lakukan pengujian yang cukup untuk menjadi percaya diri (dan untuk membuat orang lain percaya diri) bahwa hasil dan kesimpulan Anda valid.

Michael Kay
sumber
4

Saya telah bekerja di lingkungan yang sama dengan akademisi yang menulis banyak kode (matematika / sains) tetapi kemajuan mereka lambat karena alasan yang sama yang Anda gambarkan. Namun saya telah memperhatikan satu hal tertentu yang berjalan dengan baik yang saya pikir juga dapat membantu Anda: membangun dan memelihara koleksi perpustakaan khusus yang dapat digunakan di berbagai proyek. Perpustakaan ini harus menyediakan fungsi utilitas dan karenanya akan membantu menjaga proyek Anda saat ini khusus untuk domain masalah.

Misalnya, Anda mungkin harus berurusan dengan banyak transformasi koordinat di bidang Anda (ECEF, NED, lat / lon, WGS84 dll.), Jadi fungsi seperti convert_ecef_to_ned()harus pergi ke proyek baru yang disebut CoordinateTransformations. Letakkan proyek di bawah kontrol versi dan simpan di server departemen Anda sehingga orang lain dapat menggunakannya (dan semoga meningkatkannya). Kemudian setelah beberapa tahun Anda harus memiliki koleksi perpustakaan yang kuat dengan proyek Anda hanya berisi kode khusus untuk domain masalah / penelitian tertentu.

Beberapa saran yang lebih umum:

  • Selalu bertujuan untuk memodelkan masalah khusus Anda seakurat mungkin, apa pun masalahnya. Dengan begitu pertanyaan desain perangkat lunak seperti apa / di mana / bagaimana menempatkan variabel harus menjadi jauh lebih jelas untuk dijawab.
  • Saya tidak akan repot dengan pengembangan yang didorong oleh tes karena kode ilmiah menggambarkan ide dan konsep dan lebih kreatif dan fleksibel; tidak ada API untuk didefinisikan, layanan untuk dipelihara, risiko kode orang lain saat mengubah fungsionalitas dll.
jigglypuff
sumber
Jangan biarkan orang lain memperbaikinya. Kemungkinannya adalah mereka tidak mengerti tujuan dari kode dan mereka hanya akan mengacaukan segalanya.
mathreadler
@ mathreadler Nah jika itu adalah perpustakaan utilitas umum maka akan agak sulit bagi orang lain untuk mengacaukannya, itulah idenya.
jigglypuff
Mengapa sulit mengacaukan perpustakaan tujuan umum? Tidak terlalu sulit jika Anda tidak tahu apa yang Anda lakukan, atau jika Anda berusaha sangat keras, baik dalam hal ini.
mathreadler
@mathreadler Karena umumnya hanya ada satu cara untuk melakukan transformasi koordinat atau konversi unit misalnya.
jigglypuff
Biasanya ada banyak cara tergantung pada bagaimana nomor Anda disimpan dalam memori, representasi mana yang mereka gunakan dan banyak hal lainnya, yang ingin Anda kompilasi dengan CPU. Satu pengkode mungkin berasumsi bahwa setiap orang akan selalu menggunakan ganda IEEE misalnya, tetapi yang lain hampir selalu menggunakan presisi tunggal atau format ketiga yang lebih aneh. Satu coder kemudian akan menggunakan polimorfisme templat tetapi yang lain mungkin alergi terhadapnya, sepertiga bahkan lebih aneh lagi pada hard-coding segala sesuatu dalam level rendah c atau assembly.
mathreadler
3

Berikut ini adalah pendapat saya dan sangat dipengaruhi oleh jalan saya sendiri.

Pengkodean sering menimbulkan perspektif dogmatis tentang bagaimana Anda harus melakukan sesuatu. Alih-alih teknik & alat, saya pikir Anda perlu melihat nilai & biaya kumulatif untuk memutuskan strategi yang tepat.

Menulis kode yang bagus, mudah dibaca, dapat di-debuggable, dan padat membutuhkan banyak waktu & usaha. Dalam banyak kasus, mengingat horizon perencanaan yang terbatas, tidak ada gunanya melakukan ini (analisis kelumpuhan).

Seorang kolega memiliki aturan praktis; jika pada dasarnya Anda melakukan hal yang sama untuk ketiga kalinya maka investasikan upaya, jika tidak, pekerjaan cepat & kotor pantas dilakukan.

Menguji semacam itu penting, tetapi untuk satu proyek, cukup mengamati bola mata mungkin sudah cukup. Untuk hal yang substansial, pengujian & infrastruktur pengujian sangat penting. Nilai itu membebaskan Anda saat pengkodean, biayanya adalah jika tes berfokus pada implementasi tertentu maka tes juga perlu pemeliharaan. Tes juga mengingatkan Anda tentang bagaimana hal-hal yang seharusnya beroperasi.

Untuk skrip saya sendiri (sering untuk hal-hal seperti memvalidasi perkiraan probabilitas, atau serupa), saya menemukan dua hal kecil yang sangat berguna: 1. Sertakan komentar yang menunjukkan bagaimana kode digunakan. 2. Sertakan deskripsi singkat tentang mengapa Anda menulis kode. Hal-hal ini sangat jelas ketika Anda menulis kode, tetapi kejernihannya terbuang seiring waktu :-).

OOP adalah tentang menggunakan kembali kode, abstrak, enkapsulasi, anjak piutang, dll. Sangat berguna, tetapi mudah hilang jika memproduksi kode & desain berkualitas bukanlah tujuan akhir Anda. Butuh waktu & upaya untuk menghasilkan barang berkualitas.

tembaga
sumber
3

Sementara saya berpikir bahwa unit test memiliki kelebihannya, mereka memiliki nilai yang diragukan untuk pengembangan ilmiah - mereka seringkali terlalu kecil untuk menawarkan banyak nilai.

Tapi saya sangat suka tes integrasi untuk kode ilmiah:

Isolasikan sebagian kecil dari kode Anda yang dapat bekerja sendiri, misalnya pipa ETL. Kemudian tulis tes yang menyediakan data, jalankan pip etl (atau hanya langkah) dan kemudian uji bahwa hasilnya sesuai dengan harapan Anda. Sementara potongan yang diuji dapat berupa banyak kode, pengujian memberikan nilai tetap:

  1. Anda memiliki hook yang nyaman untuk mengeksekusi ulang kode Anda, yang membantu untuk sering menjalankannya.
  2. Anda dapat menguji beberapa asumsi dalam pengujian Anda
  3. Jika ada yang rusak, mudah untuk menambahkan tes yang gagal dan melakukan perbaikan
  4. Anda mengkodifikasikan input / output yang diharapkan, menghindari sakit kepala biasa yang dihasilkan dari mencoba menebak format data input.
  5. Meskipun tidak selangsing tes unit, tes TI masih membantu memecah kode Anda dan memaksa Anda untuk menambahkan beberapa batasan dalam kode Anda.

Saya sering menggunakan teknik ini, dan seringkali berakhir dengan fungsi utama yang dapat dibaca secara relatif tetapi sub-fungsi seringkali cukup panjang dan jelek, tetapi dapat dimodifikasi dan disusun kembali dengan cepat karena batas I / O yang kuat.

Sauer Kristen
sumber
2

Saya biasanya bekerja pada basis sumber yang sangat besar. Kami menggunakan semua alat yang Anda sebutkan. Baru-baru ini, saya mulai mengerjakan beberapa skrip python untuk proyek sampingan. Mereka adalah beberapa lusin hingga beberapa ratus baris paling banyak. Karena kebiasaan, saya melakukan skrip saya ke kontrol sumber. Ini bermanfaat karena saya dapat membuat cabang untuk mencoba eksperimen yang mungkin tidak berhasil. Saya dapat melakukan fork jika saya perlu menggandakan kode dan memodifikasinya untuk tujuan lain. Ini menyisakan yang asli kalau-kalau saya perlu mengeluarkannya lagi.

Untuk "unit test", saya hanya memiliki beberapa file input yang dimaksudkan untuk menghasilkan beberapa output yang diketahui yang saya periksa dengan tangan. Saya mungkin bisa mengotomatiskannya, tetapi rasanya butuh waktu lebih banyak untuk melakukan itu daripada menghemat dengan melakukannya. Mungkin tergantung pada seberapa sering saya harus memodifikasi dan menjalankan skrip. Either way, jika berhasil, lakukanlah. Jika lebih banyak masalah daripada nilainya, jangan buang waktu Anda.

pengguna1118321
sumber
2

Dengan kode penulisan - seperti halnya penulisan pada umumnya - pertanyaan utamanya adalah:

Pembaca yang mana yang Anda pikirkan? atau Siapa yang mengonsumsi kode Anda?

Hal-hal seperti pedoman pengkodean formal tidak masuk akal ketika Anda adalah satu-satunya audiens Anda.

Yang sedang berkata, di sisi lain, akan sangat membantu untuk menulis kode dengan cara, masa depan Anda, Anda dapat memahaminya segera.

Jadi "gaya yang baik" akan menjadi satu, yang paling membantu Anda. Seperti apa gaya itu adalah jawaban yang tidak bisa saya berikan.

Saya pikir Anda tidak perlu tes OOP atau Unit untuk file 150 LOC. VCS khusus akan menarik ketika Anda memiliki beberapa kode yang berkembang. Kalau .baktidak, lakukan triknya. Alat-alat ini adalah obat untuk penyakit, Anda bahkan mungkin tidak punya.

Mungkin Anda harus menulis kode Anda sedemikian rupa, sehingga bahkan jika Anda membacanya saat sedang mabuk, Anda dapat membaca, memahami dan memodifikasinya.

Thomas Junk
sumber