Saya memiliki latar belakang Java / Groovy yang kuat dan saya telah ditugaskan ke tim yang memelihara basis kode C yang cukup besar untuk perangkat lunak administratif.
Beberapa titik sakit, seperti berurusan dengan gumpalan di database atau menghasilkan laporan dalam PDF dan Excel telah dieksternalisasi ke layanan web java.
Namun, sebagai seorang pengembang Java, saya agak bingung dengan beberapa aspek kode:
- itu verbose (terutama ketika berhadapan dengan 'pengecualian')
- ada banyak metode besar (banyak 2000 + metode baris)
- tidak ada struktur data lanjutan (Saya sangat merindukan Daftar, Mengatur dan Memetakan)
- tidak ada pemisahan perhatian (SQL dicampur dengan gembira di sekitar kode)
Akibatnya saya merasa bahwa bisnis ini tersembunyi dalam banyak kode teknis dan otak saya, dibentuk dengan Object Oriented dan sejumput pemrograman Fungsional, tidak nyaman.
Sisi baik dari proyek ini adalah bahwa kode lurus ke depan: tidak ada kerangka kerja, tidak ada manipulasi kode byte saat runtime, tidak ada AOP. Dan server dapat secara bersamaan menjawab 10.000 pengguna dengan satu mesin dengan menggunakan lebih sedikit memori daripada kebutuhan java untuk meludah "hello world".
Saya ingin belajar bagaimana menulis kode C sesuai dengan prinsip-prinsip modern yang diterima secara umum. Apakah ada prinsip yang diterima secara umum tentang bagaimana C modern harus ditulis dan disusun?
Sesuatu yang mirip dengan buku 'Java Efektif', tetapi untuk C.
Edit berdasarkan jawaban dan komentar:
- Saya akan mencoba untuk menyesuaikan pola pikir saya ke kode C dan tidak mencoba untuk mencerminkannya ke OOP.
- Saya sudah mulai memindai-membaca panduan gaya pengkodean yang direkomendasikan dari komentar (Standar Pengkodean GNU dan Gaya Pengodean Kernel Linux).
- Saya kemudian akan mencoba mengusulkan gaya kode ini kepada rekan kerja saya. Bagian yang paling sulit adalah meyakinkan rekan kerja bahwa metode besar dapat dibagi menjadi bagian-bagian yang lebih kecil dan bahwa mengulangi 4 baris kode penanganan kesalahan yang sama dapat dihindari dengan bantuan metode.
sumber
Jawaban:
Saya dapat membaca dari pertanyaan Anda masalahnya bukan bahwa kode itu adalah C lama tetapi hanya pemrograman yang buruk . Sebagian besar masalah yang Anda sebutkan seperti verbositas, fungsi garis 2000+ besar, atau tidak ada pemisahan kekhawatiran berlaku untuk bahasa apa pun, C atau Java sama.
Verbositas disebutkan dalam konteks penanganan kesalahan. Anda tidak memberikan contoh jadi saya hanya dapat mengingatkan bahwa kode penanganan kesalahan juga merupakan kode . Tidak ada alasan untuk bagian berulang kode boilerplate. Faktorkan itu; baik ke fungsi atau (jika itu tidak layak untuk membuat fungsi terpisah) lakukan
goto Error;
pola dan pindahkan penanganan kesalahan dan pembersihan sumber daya keError:
bagian di bagian bawah fungsi.Jika melewatkan kesalahan pada rantai panggilan tampaknya menjadi masalah, tanyakan pada diri sendiri: apakah fungsi di sana benar - benar perlu tahu beberapa pria kecil di sini punya masalah? Mekanisme pengecualian bawaan dalam bahasa membuatnya mudah untuk dilakukan, tetapi secara umum lebih baik untuk menangani pengecualian lebih awal (dalam bahasa apa pun) sehingga kondisi kesalahan tidak mencemari logika kode tingkat tinggi. Dan jika fungsi di sana benar-benar perlu diketahui, ada cara untuk meniru pengecualian dengan
setjmp
danlongjmp
.Saya pikir satu-satunya masalah terkait C yang disebutkan adalah kurangnya wadah standar. Meskipun
Set
secara umum dapat diganti dengan array yang diurutkan danMap
(sebagian besar) dengan array berpasangan ataustruct
(jika Anda tahu set kunci sebelumnya,map[key] = value
berubah menjadis.key = value
), tetapi kenyataannya tidak ada wadah array dinamis dalam standar. Perpustakaan. Dalam C99 Anda setidaknya dapat mendeklarasikan array panjang variabel pada stack (int array[len]
) tetapi Anda harus menghitunglen
sebelumnya (biasanya tidak sulit) dan tentu saja Anda tidak dapat mengembalikannya sebagai objek stack-dialokasikan. Sebagian besar proyek berakhir dengan menulis wadah array dinamis mereka sendiri atau mengadopsi yang open-source.Pada catatan penutup, saya ingin menunjukkan bahwa saya pernah ke sana. Saya telah menjadi programmer Java yang pindah ke C ++ dan pure C. Saya ingin menyarankan "baca buku X untuk belajar C yang baik" tetapi tidak ada sama seperti tidak ada untuk Java. Cara untuk maju adalah dengan menyerap semua kerumitan bahasa dan perpustakaan standar; google banyak, banyak membaca, dan banyak kode sampai Anda mulai berpikir dalam C. Mencoba untuk menulis hal-hal dalam C seperti yang Anda lakukan di Jawa sama frustasinya dengan mencoba menulis kalimat dalam bahasa asing dengan kata-kata yang langsung diterjemahkan dari ibu Anda lidah; Anda dan pembaca akan merasa ngeri. Kabar baiknya adalah bahwa belajar pemrograman yang baik lambat tetapi belajar bahasa lain cepat. jadi jika Anda menulis kode yang layak di Jawa,
sumber
setjmp()
/longjmp()
sebagai alat yang valid: Ia bahkan tidak mencoba melakukan pembersihan. Alokasi apa pun akan dibocorkan, kunci yang ditahan tidak akan dirilis, file apa pun yang dibuka tidak akan ditutup, dan setiap inkonsistensi data sementara akan menjadi permanen. IMHO, pasangan fungsi ini pada dasarnya adalah retasan terburuk yang pernah ditemukan, dengan satu-satunya justifikasi bahwa itu mungkin untuk diterapkan. Pada akhirnya, hanya ada satu cara yang valid untuk melakukan penanganan kesalahan di C: kode kesalahan eksplisit.setjmp/longjmp
tampak ikan keluar dari air di C dan saya tidak pernah menggunakannya. Saya merasa harus memasukkannya hanya karena banyaknya tutorial / perpustakaan di internet untuk meniru pengecualian, jadi saya pikir ada orang di luar yang benar-benar menggunakannya.Saya akan merekomendasikan Anda berhati-hati apakah ini sepadan dengan waktu Anda dan uang perusahaan untuk menghabiskan sumber daya pada "memodernisasi" perangkat lunak yang berfungsi dengan kompleksitas kode rendah dan yang berkinerja baik. Ada tudung besar yang memungkinkan Anda memperkenalkan bug baru sendiri, terutama karena tampaknya ini adalah sistem yang tidak Anda kenal.
Jika Anda masih ingin turun rute itu maka saya akan menyarankan yang berikut:
Pada titik ini, Anda akan memutuskan apakah ini pantas ditelusuri atau tidak. Jika budaya perusahaan Anda tidak menghargai kegagalan maka dapatkan lampu hijau dari atasan atau manajer.
Saya pikir itu peta jalan yang cukup bagus dan membawa Anda ke mana pun Anda butuhkan. Tanpa mengetahui spesifik dari proyek ini sulit untuk banyak membantu Anda. Tolong jangan membuang penafian saya sebagai terlalu mengkhawatirkan. Banyak programmer yang hebat telah mengalahkan debu dengan mencoba menulis ulang proyek yang ada ke bahasa favorit mereka atau menggunakan alat "modern". Itu keputusan yang harus dipikirkan dengan hati-hati dan saya mendorong Anda untuk tidak nakal dan melakukannya sendiri tanpa dukungan manajemen atau bantuan dari kolega Anda.
sumber
Jika Anda lebih suka bahasa tingkat yang lebih tinggi, ada beberapa bahasa seperti C ++ atau Objective-C yang dapat dicampur dengan kode C dengan cukup mudah.
Atau, C dan C ++ cukup kompatibel. Anda mungkin bisa mengkompilasi seluruh basis kode sebagai C ++ dengan sedikit perubahan - Anda akan memiliki variabel sesekali bernama "kelas" atau "templat" yang perlu Anda ganti namanya, tetapi dalam praktiknya itu saja. (sizeof ('a') berbeda dalam C dan C ++, tapi saya rasa saya tidak pernah menggunakannya).
Jika Anda memilih rute itu, pertimbangkan bahwa pengelola berikutnya mungkin tidak terlalu lancar menggunakan C ++. Jangan terbawa suasana. Manfaatkan C ++, tetapi hanya sejauh ini seorang programmer C dapat dengan mudah memahaminya.
sumber
malloc
) dianggap praktik buruk di C. Arti dariconst
daninline
juga sangat berbeda antara C dan C ++, dan tentu saja C ++ tidak mengerti__restrict
. Jangan memperlakukan bahasa sebagai yang dapat dipertukarkan, bahkan dalam subset sumber yang dikompilasi dalam keduanya.Pada dasarnya, menulis kode C yang baik sama seperti menulis kode C ++ atau Java yang baik: Anda ingin kelas, gunakan a
struct
. Anda ingin warisan, sertakan basisstruct
sebagai anggota pertama tanpa nama. Anda ingin fungsi virtual, tambahkan pointer ke pointerstruct
fungsi statis . Dan seterusnya, dll. Ini persis apa yang dilakukan C ++ di bawah tenda, satu-satunya perbedaan adalah, bahwa itu eksplisit dalam C. Dengan demikian, Anda dapat melakukan pemrograman berorientasi objek dengan sempurna di C, itu hanya terlihat sedikit berbeda dan lebih sederhana daripada apa yang Anda digunakan untuk.Intinya, pemrograman yang baik itu tentang paradigma, bukan tentang fitur bahasa. Benar, itu selalu baik jika fitur bahasa Anda memberikan dukungan yang baik untuk paradigma yang ingin Anda gunakan, tetapi fitur bahasa bukan keharusan. Setelah Anda menyadarinya, Anda dapat menulis kode yang bagus dalam hampir semua bahasa (terlepas dari beberapa bahasa esoterik seperti Brainfuck atau INTERCAL, yaitu).
Tentu saja, masalahnya tetap bahwa pustaka C standar tidak berisi salah satu dari kelas wadah bagus yang Anda gunakan. Sayangnya, itu berarti Anda harus menggunakan milik Anda sendiri, atau mengatasi kekurangan ini dengan menggunakan array yang dialokasikan secara dinamis. Tetapi saya berani bertaruh Anda akan segera mengetahui, bahwa yang Anda perlukan adalah array dinamis (
malloc()
) dan daftar / pohon tertaut yang diimplementasikan melalui anggota pointer di dalam kelas Anda.sumber