Bagaimana cara mengatasi masalah (kompilasi) basis kode yang besar?

10

Walaupun saya bisa membuat kode, saya belum punya pengalaman dengan mengerjakan proyek-proyek besar. Apa yang saya lakukan sejauh ini adalah mengkode program kecil yang dikompilasi dalam hitungan detik (berbagai latihan c / c ++ seperti algoritma, prinsip pemrograman, ide, paradigma, atau hanya mencoba api ...) atau mengerjakan beberapa proyek kecil yang dibuat dalam bahasa skrip (python, php, js) di mana tidak diperlukan kompilasi.

Masalahnya adalah, ketika coding dalam bahasa scripting, setiap kali saya ingin mencoba jika sesuatu berfungsi - saya hanya menjalankan skrip dan melihat apa yang terjadi. Jika semuanya tidak berhasil, saya dapat dengan mudah mengubah kode dan mencobanya lagi dengan menjalankan skrip lagi dan terus melakukan itu sampai saya mendapatkan hasil yang saya inginkan .. Maksud saya adalah bahwa Anda tidak perlu menunggu apa saja untuk dikompilasi dan karena itu cukup mudah untuk mengambil basis kode besar, memodifikasinya, menambahkan sesuatu ke dalamnya, atau hanya bermain dengannya - Anda dapat melihat perubahannya secara instan.

Sebagai contoh saya akan mengambil Wordpress. Sangat mudah untuk mencoba dan mencari tahu cara membuat plugin untuk itu. Pertama Anda mulai dengan membuat plugin "Hello World" sederhana, kemudian Anda membuat antarmuka sederhana untuk panel admin untuk membiasakan diri dengan API, kemudian Anda membangunnya dan membuat sesuatu yang lebih kompleks, sementara itu mengubah tampilannya seperti beberapa. kali .. Gagasan harus mengkompilasi ulang sesuatu sebesar WP berulang-ulang, setelah setiap perubahan kecil untuk mencoba "jika berhasil" dan "bagaimana cara kerjanya / terasa" sepertinya tidak efisien, lambat dan salah.

Sekarang, bagaimana saya bisa melakukan itu dengan proyek yang ditulis dalam bahasa yang dikompilasi? Saya ingin berkontribusi pada beberapa proyek open-source dan pertanyaan ini terus menggangguku. Situasinya mungkin berbeda dari proyek ke proyek di mana beberapa dari mereka yang sebelumnya berpikir dengan bijak akan "modular" dalam beberapa cara sementara yang lain hanya akan menjadi satu gumpalan besar yang perlu dikompilasi ulang berulang kali.

Saya ingin tahu lebih banyak tentang bagaimana ini dilakukan dengan benar. Apa saja praktik umum, pendekatan dan desain proyek (pola?) Untuk mengatasinya? Bagaimana "modularitas" ini disebut di dunia programmer dan apa yang harus saya google untuk mempelajari lebih lanjut tentang ini? Apakah sering proyek tumbuh dari proporsi pemikiran pertama mereka yang menjadi masalah setelah beberapa saat? Apakah ada cara untuk menghindari kompilasi yang lama dari proyek yang tidak dirancang dengan baik? Suatu cara untuk memodulasi mereka (mungkin mengecualikan bagian-bagian program yang tidak penting sambil mengembangkan (ada ide lain?))

Terima kasih.

pootzko
sumber
4
Ob. XKCD dan relevan ThinkGeek t-shirt * 8' )
Mark Booth
1
Jika Anda bekerja pada proyek yang cukup besar dengan anggaran yang cukup besar, Anda bisa mendapatkan server pembangun untuk melakukan kompilasi untuk Anda :)
SoylentGray
@Chad - Saya tahu itu, tapi itu hanya mesin desktop gnu / linux rumah saya dan saya saat ini :)
pootzko
@Chad Ok, jadi Anda memberi tahu kami bahwa kami memerlukan server khusus untuk menangani sebagian besar Java (atau bahasa kompilasi lainnya)? Itu omong kosong total
Kolob Canyon
1
@ KolobCanyon - Tidak, saya mengatakan ada skala yang dapat Anda kerjakan yang akan membutuhkan mereka. dan mereka cukup murah sekarang karena memiliki permintaan VM yang didedikasikan untuk kompilasi cepat dan autmasi tes cukup mudah sehingga skalanya tidak sebesar itu.
SoylentGray

Jawaban:

8

Seperti yang telah dikatakan, Anda tidak pernah mengkompilasi ulang seluruh proyek setiap kali Anda membuat perubahan kecil. Alih-alih, Anda hanya mengkompilasi ulang bagian dari kode yang telah berubah, serta semua kode bergantung padanya.

Dalam C / C ++, kompilasi cukup mudah. Anda mengkompilasi menerjemahkan setiap file sumber ke dalam kode mesin (kami menyebutnya file objek * .o) dan kemudian Anda menautkan semua file objek Anda menjadi satu file besar yang dapat dieksekusi.

Sama seperti MainMa disebutkan, beberapa perpustakaan dibangun ke dalam file terpisah, yang akan dihubungkan secara dinamis pada saat run-time dengan executable. Perpustakaan ini disebut Shared Objects (* .so) di Unix dan Dynamically Linked Libraries (DLL) di Windows. Pustaka dinamis memiliki banyak keuntungan, salah satunya adalah Anda tidak perlu mengkompilasi / menautkannya, kecuali jika kode sumbernya berubah secara efektif.

Ada alat otomasi bangunan yang membantu Anda:

  • Tentukan ketergantungan antara berbagai bagian dari pohon sumber Anda.
  • Luncurkan kompilasi tepat waktu dan bijaksana hanya di bagian yang telah dimodifikasi.

Yang paling terkenal (make, ant, maven, ...) dapat mendeteksi secara otomatis bagian mana dari kode yang telah diubah sejak kompilasi terakhir, dan objek / biner apa yang perlu diperbarui.

Namun, ini merupakan biaya (relatif kecil) karena harus menulis "membangun skrip". Ini adalah file yang berisi semua informasi tentang build Anda, seperti mendefinisikan target dan dependensinya, menentukan kompiler mana yang Anda inginkan dan opsi mana yang digunakan, mendefinisikan lingkungan build Anda, jalur perpustakaan Anda, ... Anda mungkin pernah mendengar tentang Makefiles (sangat umum di dunia Unix), atau build.xml (sangat populer di dunia Java). Inilah yang mereka lakukan.

rahmu
sumber
2
Semut (Jawa) tidak dapat menentukan apa yang perlu dikompilasi ulang. Ini menangani bagian sepele dari pekerjaan, mengkompilasi ulang kode sumber yang diubah, tetapi sama sekali tidak memahami dependensi kelas. Kami mengandalkan IDE untuk itu, dan mereka salah jika tanda tangan metode diubah dengan cara yang tidak memerlukan perubahan kode panggilan.
kevin cline
@ kevincline Saya yang kedua ini - ANT mengkompilasi segalanya kecuali Anda menentukan sesuatu yang berbeda dalam build.xmlfile
Kolob Canyon
7

Anda tidak mengkompilasi ulang seluruh proyek setiap saat. Misalnya, jika itu adalah aplikasi C / C ++, ada kemungkinan itu akan dipisahkan menjadi pustaka (DLL di Windows), setiap pustaka dikompilasi secara terpisah.

Proyek itu sendiri umumnya dikompilasi setiap hari di server khusus: itu adalah build malam. Proses ini dapat memakan banyak waktu, karena tidak hanya mencakup waktu kompilasi, tetapi juga waktu yang dihabiskan untuk menjalankan tes unit, tes lain, dan proses lainnya.

Arseni Mourzenko
sumber
3
Jika saya tidak mengkompilasi ulang semuanya maka kapan saya akan punya waktu untuk bermain dengan Trebuchet
SoylentGray
5

Saya pikir apa yang semua jawaban sejauh ini telah singgung juga, adalah bahwa proyek perangkat lunak besar hampir selalu dipecah menjadi potongan-potongan yang jauh lebih kecil. Setiap bagian biasanya disimpan dalam file itu sendiri.

Potongan-potongan ini dikompilasi secara individual untuk membuat objek. Benda-benda tersebut kemudian dihubungkan bersama untuk membentuk produk akhir. [Bisa dibilang, ini seperti membangun barang-barang dari Lego. Anda tidak mencoba untuk mencetak benda terakhir dari selembar plastik besar, sebaliknya Anda menggabungkan banyak potongan kecil untuk membuatnya.]

Memecah proyek menjadi beberapa bagian yang dikompilasi secara individual memungkinkan beberapa hal yang rapi terjadi.

Bangunan Bertambah

Pertama, ketika Anda mengganti satu potong, Anda biasanya tidak perlu mengkompilasi ulang semua bagian. Secara umum, selama Anda tidak mengubah cara bagian lain berinteraksi dengan bagian Anda, yang lain tidak perlu dikompilasi ulang.

Ini memunculkan ide bangunan inkremental . Saat melakukan pembangunan bertahap, hanya potongan-potongan yang dipengaruhi oleh perubahan yang dikompilasi ulang. Ini sangat mempercepat waktu pengembangan. Benar, Anda mungkin masih harus menunggu semuanya untuk ditata kembali, tetapi itu masih penghematan karena harus mengkompilasi ulang dan menautkan kembali semuanya. (BTW: Beberapa sistem / bahasa mendukung penautan tambahan sehingga hanya hal-hal yang diubah yang harus dihubungkan kembali. Biaya untuk ini biasanya dalam kinerja dan ukuran kode yang buruk.)

Pengujian Unit

Hal kedua yang memungkinkan Anda melakukan hal-hal kecil adalah melihat secara individual menguji bagian-bagian tersebut sebelum digabungkan. Ini dikenal sebagai Unit Testing . Dalam Pengujian Unit, setiap unit diuji secara individual sebelum diintegrasikan (dikombinasikan) dengan sisa sistem. Tes unit biasanya ditulis sehingga mereka dapat berjalan dengan cepat tanpa melibatkan sisa sistem.

Kasus yang membatasi penerapan pengujian terlihat di Test Driven Development (TDD). Dalam model pengembangan ini, tidak ada kode yang ditulis / dimodifikasi kecuali untuk memperbaiki tes yang gagal.

Membuatnya Lebih Mudah

Jadi, meruntuhkan hal-hal tampaknya baik, tetapi tampaknya juga banyak pekerjaan yang diperlukan untuk membangun proyek: Anda perlu menentukan bagian kami yang berubah dan apa yang tergantung pada bagian itu, menyusun setiap bagian, dan kemudian menghubungkan semuanya bersama-sama.

Untungnya, pemrogram malas *, sehingga mereka menemukan banyak alat untuk membuat pekerjaan mereka lebih mudah. Untuk itu, banyak alat telah ditulis untuk mengotomatiskan tugas di atas. Yang paling terkenal dari ini telah disebutkan (make, ant, maven). Alat-alat ini memungkinkan Anda untuk menentukan bagian mana yang perlu disatukan untuk membuat proyek akhir Anda dan bagaimana bagian itu saling bergantung (yaitu jika Anda mengubahnya, ini perlu dikompilasi ulang). Hasilnya adalah bahwa mengeluarkan hanya satu perintah tidak menggambarkan apa yang perlu dikompilasi ulang, mengkompilasinya, dan menautkan kembali segalanya.

Tapi itu masih menyisakan bagaimana hal-hal berhubungan satu sama lain. Itu banyak pekerjaan dan seperti yang saya katakan sebelumnya, programmer malas. Jadi mereka datang dengan kelas alat lain. Alat-alat ini telah ditulis untuk menentukan dependensi untuk Anda! Seringkali alat tersebut merupakan bagian dari Integrated Development Environments (IDEs) seperti Eclipse dan Visual Studio, tetapi ada juga beberapa yang mandiri yang digunakan untuk aplikasi umum dan spesifik (makedep, QMake untuk program Qt).

* Sebenarnya, programmer tidak benar-benar malas, mereka hanya suka menghabiskan waktu mereka mengerjakan masalah, tidak melakukan tugas berulang yang dapat diotomatisasi oleh suatu program.

jerny
sumber
5

Inilah daftar barang yang bisa Anda coba mempercepat pembuatan C / C ++:

  • Apakah Anda siap untuk hanya membangun kembali apa yang telah berubah? Sebagian besar lingkungan melakukan ini secara default. Tidak perlu mengkompilasi ulang file jika ada atau tidak ada header yang berubah. Demikian pula, tidak ada alasan untuk membangun kembali dll / exe jika semua yang tertaut dalam objs / lib tidak berubah.
  • Tempatkan hal-hal pihak ketiga yang tidak pernah berubah dan header terkait di beberapa area perpustakaan kode baca saja. Anda hanya perlu header dan binari terkait. Anda seharusnya tidak perlu membangun kembali ini dari sumber selain mungkin sekali.
  • Saat membangun kembali semuanya, dua faktor pembatas dalam pengalaman saya adalah jumlah core dan kecepatan disk . Dapatkan quad core gemuk, mesin hyperthreaded dengan hdd yang sangat bagus dan kinerja Anda akan meningkat. Pertimbangkan solid state drive - ingat yang murah mungkin lebih buruk daripada hdd yang baik. Pertimbangkan menggunakan raid untuk menambah hdd Anda
  • Gunakan sistem build terdistribusi seperti Incredibuild yang akan membagi kompilasi di stasiun kerja lain di jaringan Anda. (Pastikan Anda memiliki jaringan yang solid).
  • Setup build unity untuk menyelamatkan Anda dari memuat ulang file header secara konstan.
Doug T.
sumber
Dalam pengalaman saya (tidak banyak, tetapi juga) kecepatan disk mulai menjadi tidak relevan jika proyek Anda melampaui "sangat kecil". Pikirkan saja apa yang Anda katakan di poin berikut: Anda menggunakan jaringan untuk mempercepat kompilasi. Jika disk adalah hambatan besar, beralih ke jaringan sepertinya bukan langkah yang baik.
R. Martinho Fernandes
Solusi murah lainnya adalah dengan mengompilasi dalam tmpfs. Dapat sangat meningkatkan kinerja jika proses kompilasi terikat IO.
Artefact2
4

Gagasan harus mengkompilasi ulang sesuatu sebesar WP berulang-ulang, setelah setiap perubahan kecil untuk mencoba "jika berfungsi" dan "bagaimana cara kerjanya / terasa" sepertinya tidak efisien, lambat dan salah.

Mengeksekusi sesuatu yang ditafsirkan juga sangat tidak efisien dan lambat, dan (bisa dibilang) salah. Anda mengeluh tentang persyaratan waktu pada PC dev, tetapi tidak kompilasi menyebabkan persyaratan waktu pada PC pengguna , yang bisa dibilang jauh lebih buruk.

Lebih penting lagi, sistem modern dapat melakukan pembangunan kembali bertahap yang cukup canggih dan tidak umum untuk mengkompilasi ulang semuanya untuk perubahan kecil - sistem yang dikompilasi dapat mencakup komponen skrip, terutama yang umum untuk hal-hal seperti UI.

DeadMG
sumber
1
Saya percaya pertanyaan saya tidak dimaksudkan untuk ditafsirkan vs menyusun debat pendekatan. Sebagai gantinya saya hanya meminta saran tentang bagaimana pengembangan proyek besar (dikompilasi) dilakukan dengan benar. Terima kasih atas ide membangun kembali secara bertahap.
pootzko
@ bootzko: Yah, cukup tidak adil untuk membahas kelemahan kompilasi ketika Anda tidak juga berbicara tentang kelemahan interpretasi.
DeadMG
1
bukan itu. ini debat lain dan tidak ada hubungannya dengan pertanyaan saya. Saya tidak mengatakan itu adalah sesuatu yang tidak boleh dibicarakan. seharusnya, tetapi tidak di sini.
pootzko
@ bootzko: Maka Anda tidak harus mendedikasikan sebagian besar pertanyaan Anda untuk menyebutkan apa yang tidak Anda sukai tentang kompilasi. Anda seharusnya menulis sesuatu yang jauh lebih pendek dan lebih cepat, seperti, "Bagaimana waktu kompilasi proyek besar dapat dikurangi?".
DeadMG
Saya tidak tahu saya harus bertanya kepada seseorang tentang bagaimana saya "harus" mengajukan pertanyaan saya ..? : OI menulisnya seperti yang saya lakukan untuk lebih menjelaskan sudut pandang saya sehingga orang lain dapat lebih memahami dan menjelaskan kepada saya bagaimana mencapai hal yang sama / mirip dengan bahasa yang dikompilasi. Saya lagi - tidak - meminta siapa pun untuk memberi tahu saya jika bahasa yang ditafsirkan menyebabkan persyaratan waktu yang lebih buruk pada PC pengguna. Saya tahu itu, dan itu tidak ada hubungannya dengan pertanyaan saya - "bagaimana caranya dengan bahasa yang dikompilasi", maaf. Orang lain tampaknya sudah tahu apa yang saya tanyakan, jadi saya tidak berpikir pertanyaan saya tidak cukup jelas ..
pootzko
4
  • Membangun Kembali Sebagian

Jika proyek mengimplementasikan ketergantungan kompilasi DAG yang tepat maka Anda dapat pergi dengan hanya mengkompilasi ulang file objek yang mempengaruhi perubahan Anda.

  • Proses Kompilasi Berganda

Juga dengan asumsi DAG dependensi kompilasi yang tepat, Anda dapat mengkompilasi menggunakan beberapa proses. Satu pekerjaan per inti / CPU adalah norma.

  • Tes yang dapat dieksekusi

Anda dapat membuat beberapa file yang dapat dieksekusi untuk pengujian yang hanya menautkan file objek tertentu.

dietbuddha
sumber
2

Selain jawaban MainMa, kami juga baru saja meningkatkan mesin yang sedang kami kerjakan. Salah satu pembelian terbaik yang kami lakukan adalah SSD untuk saat Anda tidak dapat membantu tetapi untuk mengkompilasi ulang seluruh proyek.

Saran lain adalah mencoba kompiler yang berbeda. Kembali pada hari itu, kami beralih dari kompiler Java ke Jikes dan sekarang kami telah beralih menggunakan kompiler yang dibundel dengan Eclipse (tidak tahu apakah ia memiliki nama) yang mengambil keuntungan lebih baik dari prosesor multicore.

Proyek file 37.000 kami membutuhkan waktu sekitar 15 menit untuk dikompilasi dari awal sebelum kami melakukan perubahan ini. Setelah perubahan itu dikurangi menjadi 2-3 menit.

Tentu saja, ada baiknya menyebutkan poin MainMa lagi. Jangan mengkompilasi ulang seluruh proyek setiap kali Anda ingin melihat perubahan.

RP.
sumber