Solusi sederhana vs kompleks (tapi efisien kinerja) - mana yang harus dipilih dan kapan?


28

Saya telah pemrograman selama beberapa tahun dan sering menemukan diri saya pada dilema.

Ada dua solusi -

  • satu sederhana satu yaitu pendekatan sederhana, lebih mudah dimengerti dan dipelihara. Ini melibatkan beberapa redundansi, beberapa pekerjaan tambahan (IO ekstra, pemrosesan ekstra) dan karenanya bukan solusi yang paling optimal.
  • tetapi yang lain menggunakan pendekatan yang kompleks, sulit diimplementasikan, sering melibatkan interaksi antara banyak modul dan merupakan solusi yang efisien kinerja.

Solusi mana yang harus saya perjuangkan ketika saya tidak memiliki SLA kinerja keras untuk dipenuhi dan bahkan solusi sederhana dapat memenuhi SLA kinerja? Saya merasa jijik di antara sesama pengembang untuk solusi sederhana.

Apakah praktik yang baik untuk menghasilkan solusi kompleks yang paling optimal jika kinerja Anda SLA dapat dipenuhi oleh solusi sederhana?


10
lihat: Bagaimana cara saya menghindari "Intuisi Optimasi Buruk Pengembang"? "Sayangnya, pengembang umumnya memiliki intuisi yang mengerikan tentang di mana masalah kinerja dalam suatu aplikasi sebenarnya akan ...."
agas

1
Akankah "bukan yang paling optimal" masih "cukup baik"? Kemudian tetap dengan itu.

8
Ya. " Le mieux est l'ennemi du bien. " Voltaire. ("Sempurna adalah musuh yang baik.") Cukup bagus cukup baik - sampai pengujian kinerja mengatakan sebaliknya.
David Hammen

Saya menemukan bahwa (secara umum) sederhana menyiratkan efisien. Jadi seringkali tidak perlu kompromi.
Dan

2
“Tampaknya kesempurnaan dicapai bukan ketika tidak ada lagi yang ditambahkan, tetapi ketika tidak ada lagi yang harus dihapus.” - Antoine de Saint-Exupery
keuleJ

Jawaban:


58

Solusi mana yang harus saya perjuangkan ketika saya tidak memiliki SLA kinerja keras untuk dipenuhi dan bahkan solusi sederhana dapat memenuhi SLA kinerja?

Yang sederhana. Memenuhi spec, lebih mudah dimengerti, lebih mudah untuk dipelihara, dan mungkin jauh lebih sedikit buggy.

Apa yang Anda lakukan dalam mendukung solusi efisien kinerja adalah memperkenalkan generalisasi spekulatif dan optimisasi prematur ke dalam kode Anda. Jangan lakukan itu! Kinerja bertentangan dengan hampir setiap 'rekayasa' perangkat lunak lain yang ada (keandalan, rawatan, keterbacaan, pengujian, dapat dipahami, ...). Mengejar kinerja saat pengujian menunjukkan bahwa benar-benar ada kebutuhan untuk mengejar kinerja.

Jangan mengejar kinerja ketika kinerja tidak masalah. Bahkan jika itu penting, Anda hanya harus mengejar kinerja di area-area di mana pengujian menunjukkan bahwa hambatan kinerja ada. Jangan biarkan masalah kinerja menjadi alasan untuk mengganti simple_but_slow_method_to_do_X()dengan versi yang lebih cepat jika versi sederhana itu tidak muncul sebagai hambatan.

Peningkatan kinerja hampir pasti terbebani dengan sejumlah masalah bau kode. Anda telah menyebutkan beberapa pertanyaan: Pendekatan yang rumit, sulit diimplementasikan, penggabungan yang lebih tinggi. Apakah itu benar-benar layak untuk diseret?


jawaban Anda sangat membantu
MoveFast

1
Sesederhana mungkin, tetapi tidak sederhana; Secepat mungkin, tetapi tidak lebih cepat; dll
user606723

2
"Jika ragu, gunakan kekerasan";)
tdammers

Komentar dalam kode dapat bersifat katarsis dan membantu di sini. Sebuah komentar kecil yang menunjukkan solusi + kompleks yang cepat, dan mengapa Anda tidak menggunakannya, dapat membuat Anda merasa kurang seperti Anda mengabaikan algoritma optimal. Dan itu dapat membantu pengelola memahami pilihan Anda dan mengarahkan mereka ke arah yang benar jika optimasi benar-benar diperlukan nanti.
TheAtomicOption

12

Jawaban Singkat: Lebih suka solusi sederhana daripada rumit, dan ingat prinsip KISS dan YAGNI

Karena persyaratan awal proyek dan perangkat lunak tidak pernah sempurna, itu memerlukan perubahan ketika aplikasi dikembangkan / digunakan. Pendekatan berulang dalam fase pengembangan adalah pertandingan yang sangat baik untuk memulai hal-hal sederhana dan memperluasnya sesuai kebutuhan. Solusi paling sederhana memiliki ruang untuk fleksibilitas dan lebih mudah dirawat.

Selain itu, mencoba untuk menjadi pintar dan menempatkan beberapa optimasi tambahan sambil tetap membangun aplikasi Anda bukanlah praktik yang baik dan mungkin terlalu memperumit solusi Anda. Seperti diketahui, "premature optimization is the root of all evil"- dari buku Knuth


1
@ Mojjumber, tidak ada masalah dan itu benar-benar esensi apa yang kita sebagai programmer harus peduli di tempat pertama.
EL Yusubov

8

Ambil pelajaran dari Knuth di sini: "Kita harus melupakan efisiensi kecil, katakanlah sekitar 97% dari waktu: optimasi prematur adalah akar dari semua kejahatan".

Pikirkan solusi Anda dalam urutan ini: Pertama, selalu, benar. Kedua, tingkatkan kejelasan dan kesederhanaan. Ketiga, dan hanya ketika Anda dapat menunjukkan kebutuhan, efisiensi.

Menambahkan efisiensi hampir selalu akan membebani Anda sesuatu yang penting, dan karenanya hanya harus dikejar ketika Anda tahu Anda perlu.


4
Perhatikan bahwa ini tidak berarti Anda tidak boleh menulis implementasi yang baik sejak awal.

@ ThorbjørnRavnAndersen: tentu saja, itulah maksud dari dua poin pertama.
simon

1
@simon kutipan sering digunakan sebagai alasan untuk memilih sembarangan,

Tentang poin kedua Anda: Saya memiliki seorang kolega yang cukup sering menyatakan bahwa ia lebih memilih kode yang terstruktur dan bersih dengan salah sebelum spageti yang benar.
Buhb

@ ThorbjørnRavnAndersen orang yang tidak kompeten akan menggunakan apa saja untuk alasan. Tidak berdampak pada nilai pemikiran asli.
simon

7

Kesederhanaan adalah prasyarat keandalan . Jika Anda memiliki solusi sederhana yang berfungsi, tentu saja lakukanlah! Jauh lebih mudah untuk mengoptimalkan program kerja daripada membuat program yang optimal bekerja. Juga jangan lupa tentang hukum Moore : jika solusi sederhana Anda memenuhi tujuan kinerja hari ini, itu mungkin akan menghancurkan mereka 1 dalam satu atau dua tahun.


1 Tidak ada jaminan di sana, karena sebagaimana dicatat oleh Jimmy Hoffa dalam komentarnya di bawah ini, hukum Moore memiliki batasnya.


Anda lupa tentang hukum Moore lainnya yang menyatakan, "Ups, tentang hukum pertamaku .." Maaf bos, hukum Moore tidak ada lagi (pun pun). Saya tidak setuju dengan sisa poin Anda, saya hanya akan setidaknya keberatan bagian terakhir di sana.
Jimmy Hoffa

2
Maaf, tapi dalam semua pengalaman saya di industri ini. "work set" meningkat JAUH lebih cepat dari kecepatan perangkat keras kami, yang secara konsisten ditingkatkan. Sungguh, saya hanya akan menghapus titik hukum Moore.
user606723

@ user606723 Pertumbuhan titik "set kerja" adalah ortogonal untuk pertanyaan "dioptimalkan atau sederhana": beban kerja akan menyusul mereka terlepas dari solusi apa yang mereka implementasikan. Titik memasukkan hukum Moore ke dalam campuran adalah untuk menunjukkan bahwa bahkan jika solusi sederhana berada di bawah tekanan kinerja pada saat penulisan, tekanan akan berkurang ketika perangkat keras lebih cepat tersedia.
dasblinkenlight

@dasblinkenlight, pertumbuhan workset tidak lebih ortogonal terhadap pertanyaan daripada hukum moore. Inti dari membawa workset ke masalah adalah bahwa jika solusi sederhana berada di bawah tekanan kinerja pada saat rilis, kinerja akan tidak mencukupi dalam waktu dekat karena peningkatan workset menghancurkan setiap peningkatan kinerja yang dicapai oleh perangkat keras yang ditingkatkan. Sementara saya semua untuk perangkat lunak yang sederhana, dapat diandalkan dan dipelihara, merilis perangkat lunak yang sudah di bawah tekanan kinerja pada rilis dan mengharapkan hukum moore untuk meratakannya adalah filosofi yang mengerikan.
user606723

3

Apakah praktik yang baik untuk menghasilkan solusi kompleks yang paling optimal jika kinerja Anda SLA dapat dipenuhi oleh solusi sederhana?

Optimal adalah kata yang ambigu!

Pada akhirnya, jika ada banyak risiko karena harus mempertahankan yang kompleks, dan jika yang sederhana "cukup baik", saya selalu keliru di sisi yang sederhana.

Tambahkan risiko yang kompleks tidak cukup baik, maka KISS mungkin jawaban yang tepat.


2

Saya lebih suka yang sederhana. Menurut pendapat saya optimisasi prematur menyebabkan masalah sebanyak yang mereka pecahkan. Dalam banyak kasus desain yang baik memungkinkan Anda untuk mengubah implementasi yang diberikan di masa depan, jika mereka menjadi hambatan.

Jadi pada intinya - saya akan mendesainnya sefleksibel mungkin, tetapi tidak akan mengorbankan kesederhanaan demi fleksibilitas terlalu banyak.


2

Yang mana lebih murah?

Sebagian besar waktu, solusi sederhana yang sedikit lebih lambat akan dapat diterima dalam hal kinerja, dan kesederhanaan membuatnya lebih murah untuk dikembangkan, dipelihara, dan akhirnya diganti.

Di sisi lain, kadang-kadang kecepatan sangat penting, dan keuntungan finansial yang berasal dari peningkatan kecepatan kecil sekalipun bisa jauh lebih besar daripada peningkatan biaya solusi yang lebih rumit. Misalnya, mengurangi waktu 0,01 untuk menyelesaikan transaksi dapat membuat sistem perdagangan efek jauh lebih menguntungkan. Peningkatan 10% dalam efisiensi sistem yang mendukung beberapa juta pengguna dapat berarti pengurangan biaya server yang signifikan.

Jadi, pertanyaan yang harus Anda tanyakan pada diri sendiri adalah: Apakah menggunakan solusi yang kompleks memiliki dampak yang cukup pada bottom line untuk membayar biaya tambahan? Sebenarnya, Anda mungkin harus meminta klien Anda untuk memutuskan karena mereka membayar tagihan dan menuai manfaat potensial. Salah satu pilihan yang baik adalah pergi dengan solusi sederhana terlebih dahulu, dan menawarkan solusi yang lebih kompleks sebagai peningkatan yang mungkin. Itu memungkinkan Anda mengaktifkan dan menjalankan sistem Anda dan memberi klien Anda sesuatu untuk memulai pengujian, dan pengalaman itu dapat menginformasikan keputusan untuk mengimplementasikan (atau tidak mengimplementasikan) solusi yang lebih rumit.


2

Ketika mengevaluasi dua pendekatan, yang satu lebih sederhana tetapi kurang efisien sementara yang lain lebih kompleks dan lebih efisien, kita harus mempertimbangkan masalah dan domain proyek.

Pertimbangkan proyek perangkat lunak multi-miliar untuk industri perawatan kesehatan yang telah merencanakan masa pakai selama lebih dari 15 tahun pemeliharaan dan penggunaan +20 tahun. Dengan demikian, kinerja proyek jelas tidak akan menjadi masalah, tetapi kompleksitas dan struktur proyek dapat menyebabkan masalah besar untuk pemeliharaan proyek, yang berlangsung minimal selama 15 tahun. Kemampu-rawatan dan kesederhanaan datang sebelum apa pun.

Kemudian, pertimbangkan contoh lain. Mesin game konsol yang seharusnya memberi daya pada game-game perusahaan yang akan datang untuk 5 tahun ke depan. Karena permainan adalah program yang sangat terbatas sumber daya, efisiensi berjalan sebelum pemeliharaan dalam banyak kasus. Menulis sendiri struktur data dan algoritme Anda yang sangat spesifik untuk beberapa tugas dapat menjadi sangat penting bahkan jika itu bertentangan dengan segala jenis "praktik terbaik" pengembangan perangkat lunak. Contoh yang baik dari hal ini adalah Desain Berorientasi Data di mana Anda menyimpan data Anda dalam array data yang serupa, bukan pada objek yang sebenarnya. Ini untuk meningkatkan referensi lokalitas dan dengan demikian meningkatkan efisiensi cache CPU. Tidak praktis, tetapi sangat penting dalam domain yang diberikan.


1

Ini selalu pertanyaan yang sulit dan saya melihat jawaban berayun satu arah, jadi saya akan memainkan permainan untuk sisi lain, meskipun saya tidak mengklaim salah satu jawaban itu benar, itu adalah topik yang sangat lembut dan kasus per kasus.

Satu hal tentang solusi yang kompleks namun berkinerja tinggi adalah Anda selalu bisa mendokumentasikan hal yang tidak pernah terjadi. Saya biasanya penggemar kode dokumentasi diri, tetapi saya juga penggemar perangkat lunak yang merespons dalam waktu yang membuat saya merasa itu tidak memperlambat saya. Jika Anda menggunakan solusi yang kompleks namun berkinerja tinggi, pertimbangkan apa yang dapat Anda lakukan untuk membuatnya tidak terlalu buruk:

Bungkus dalam sebuah antarmuka, masukkan ke dalam perakitan sendiri, mungkin bahkan semua proses itu sendiri. Buatlah selungkup longgar mungkin dengan dinding abstraksi setebal mungkin untuk menghindari kebocoran . Tulis banyak unit test untuk menyimpan regresi di masa depan.

Dokumentasikan dalam kode, bahkan pertimbangkan untuk menulis beberapa dokumentasi nyata. Pikirkan tentang struktur data yang kompleks dan bagaimana mereka didokumentasikan, bayangkan mencoba memahami implementasi salah satunya dari kode tanpa buku struktur data / artikel wikipedia untuk menjelaskannya. Namun kita semua menerima bahwa struktur data yang rumit ini sebenarnya adalah hal-hal yang baik dan bermanfaat bagi seseorang untuk mengimplementasikannya dalam bahasa kita.

Ingatlah bahwa kita semua mengirim pesan pada tumpukan TCP / IP yang mungkin sama haramnya dengan kode yang bisa didapat jika ada di antara kita yang melihatnya, secara tegas sehingga ia melakukan seperti yang kita semua juga membutuhkannya. Mungkin masalah Anda tidak memerlukan tingkat optimasi ini, mungkin memang demikian, tetapi berhati-hatilah ketika menangani pertanyaan ini karena kita semua harus dari waktu ke waktu: Ada naga di sana.


0

Saya datang di ini bekerja di daerah di mana tidak ada SLA kinerja Ketika datang ke penyaji offline dalam grafik komputer, tidak ada "kinerja yang memuaskan" bagi pengguna, karena mereka sudah mengeluarkan sejumlah besar uang untuk mendistribusikan komputasi di cloud dan membuat pertanian bahkan dengan penyaji mutakhir untuk menghasilkan gambar dan bingkai berkualitas-produksi untuk film, misalnya

Tetapi saya harus mengatakan sebagai salah satu yang bekerja di domain ini selama bertahun-tahun bahwa solusi apa pun yang secara signifikan menurunkan pemeliharaan demi efisiensi sebenarnya bekerja melawan persyaratan kinerja yang selalu berubah. Karena jika Anda tidak dapat secara efektif mempertahankan solusi Anda selama bertahun-tahun yang akan datang karena banyak hal bergeser di bawah kaki Anda (baik dalam hal kode di sekitarnya dan apa yang diharapkan pengguna sebagai pesaing terus mengungguli satu sama lain), maka solusi Anda sudah bekerja menuju keusangan dan di membutuhkan penggantian grosir.

Saya tidak melihat tujuan akhir dari profiler seperti VTune sebagai cara untuk membuat kode saya berjalan lebih cepat. Nilai tertinggi mereka adalah memastikan saya tidak menurunkan produktivitas saya untuk memenuhi tuntutan kinerja yang terus meningkat. Jika saya benar-benar harus menerapkan beberapa optimasi mikro yang terlihat kotor, maka profiler tersebut, dikombinasikan dengan menjalankannya terhadap kasus pengguna dunia nyata (dan bukan beberapa kasus uji yang saya bayangkan mungkin penting), memastikan saya menerapkan yang tampak seperti gross-looking optimisasi sangat, sangat bijaksana untuk hanya hotspot teratas yang muncul serta sangat hati-hati mendokumentasikan mereka karena saya pasti akan harus meninjau kembali dan mempertahankan dan mengubah dan mengubahnya untuk tahun-tahun berikutnya yang akan datang jika solusi itu tetap layak.

Dan terutama jika solusi Anda yang dioptimalkan melibatkan lebih banyak kopling, maka saya benar-benar akan enggan menggunakannya. Di antara metrik yang paling berharga yang saya hargai di bidang kinerja-kritis dari basis kode adalah decoupling (seperti dalam meminimalkan jumlah informasi yang dibutuhkan sesuatu untuk bekerja, yang juga meminimalkan kemungkinan diperlukannya perubahan kecuali secara langsung membutuhkan perubahan). ), karena area kritis tersebut secara signifikan melipatgandakan alasan untuk hal-hal berubah. Yang berarti semakin sedikit informasi yang diperlukan untuk bekerja, semakin sedikit alasan untuk perubahan, dan meminimalkan alasan untuk perubahan benar-benar merupakan bagian besar dari peningkatan produktivitas di bidang fokus khusus saya karena segala sesuatu harus terus berubah pula (kami akan menjadi usang dalam setahun jika tidak),

Bagi saya solusi terbesar dan paling efektif yang saya temukan adalah solusi di mana efisiensi dan pemeliharaan dan produktivitas tidak bertentangan satu sama lain. Pencarian saya adalah mencoba membuat konsep-konsep ini selaras yang bisa dibuat orang.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.