C ++ lembar contekan singkatan dan banyak lagi. Bagian 2: "dan tidak hanya"

Ini adalah bagian kedua dan terakhir dari lembar contekan singkatan saya yang harus diketahui oleh pengembang C ++. C ++ disebutkan di sini hanya karena saya membuat lembar cheat terutama untuk diri saya sendiri, dan saya hanya pengembang C ++ yang sama.

Bahkan, bagian ini berisi konsep-konsep yang ruang lingkupnya tidak terbatas pada C ++. Jadi seleksi mungkin menarik bagi khalayak yang lebih luas.



Seperti pada bagian pertama , singkatan dikelompokkan, jika itu masuk akal. Jika tidak masuk akal, mereka terdaftar berdasarkan abjad.

Konkurensi dan operasi atom:
CAS
ABA
FAA
RCU

Penyimpanan data:
ASAM
CAP
PACELC
DASAR

Prinsip Pengembangan Perangkat Lunak:
KERING
KISS
YAGNI
NIH
FTSE
GRASP
SOLID

Lainnya:
ABI
SAPI
FBC, FBCP
LRU

Operasi Konkurensi dan Atom


Cas


Bandingkan dan Tukar. Perbandingan dengan pertukaran. Ini adalah instruksi atom dengan tiga argumen: variabel atom atau alamat memori, nilai yang diharapkan, nilai baru. Jika dan hanya jika nilai variabel cocok dengan nilai yang diharapkan, variabel menerima nilai baru dan instruksi berhasil diselesaikan. CAS hanya mengembalikan nilai Boolean (dan kemudian dapat disebut Bandingkan dan Set), atau jika gagal, CAS juga mengembalikan nilai saat ini dari argumen pertama.

Kode palsu
bool cas(int* addr, int& expected, int new_value) { if (*addr != expected) { expected = *addr; return false; } *addr = new_value; return true; } 

Dalam C ++, CAS diwakili oleh std::atomic<T>::compare_exchange_weak metode std::atomic<T>::compare_exchange_weak , std::atomic<T>::compare_exchange_strong dan fungsi bebas std::atomic_compare_exchange_weak , std::atomic_compare_exchange_strong . Perbedaan antara * lemah dan * kuat adalah bahwa yang pertama dapat menghasilkan hasil negatif palsu. Yaitu jika nilainya diharapkan, mereka akan mengembalikan false dan tidak akan menggantinya dengan yang baru. Alasan keberadaan * operasi lemah adalah bahwa pada beberapa arsitektur * kuat relatif mahal. Dalam kebanyakan kasus, instruksi CAS berputar dalam satu loop (disebut loop CAS), jadi menggunakan * lemah sebagai ganti * kuat tidak akan mengubah logika, tetapi itu dapat meningkatkan kinerja.

Instruksi CAS digunakan untuk mengimplementasikan primitif sinkronisasi (seperti mutex dan semaphores) dan algoritma bebas kunci. Seringkali menyebabkan masalah ABA .

Baca lebih lanjut: sekali (Rusia) , dua (Inggris)

ABA


Masalah ABA. Masalah ABA. Masalah ini muncul dalam algoritma paralel berdasarkan perbandingan dengan pertukaran (lihat CAS ), misalnya, dalam algoritma bebas kunci. Intinya adalah bahwa thread membaca nilai variabel atom, melakukan sesuatu yang lain dan memperbarui variabel ini melalui perbandingan dengan pertukaran. Yaitu logika aliran adalah sebagai berikut: jika variabel masih berisi nilai sebelumnya, maka tidak ada yang berubah, semuanya dalam urutan. Tapi ini mungkin tidak benar. Deskripsi masalah yang lebih formal:

  • thread 1 membaca nilai variabel, sama dengan A
  • utas 1 sedang dipaksa keluar, utas 2 sedang dimulai
  • thread 2 mengubah nilai variabel dari A ke B, membuat banyak perubahan (mengubah beberapa nilai yang terkait dengan variabel atau hanya membebaskan memori), dan sekali lagi mengubah nilai - dari B ke A
  • utas 1 melanjutkan operasi, membandingkan nilai yang diperoleh sebelumnya dengan yang sekarang dan menyimpulkan bahwa tidak ada yang berubah

Kemungkinan solusi untuk masalah ini:

  1. Yang paling sederhana dan paling jelas adalah menggunakan kunci. Ini akan menghasilkan algoritma thread-safe yang biasa dengan bagian kritis. Tapi itu akan berhenti menjadi bebas dari kunci. Tetapi jika datang ke CAS dan ABA , maka ini kemungkinan besar bukan pilihan.
  2. Tambahkan label khusus ke nilai yang dibandingkan. Misalnya, penghitung jumlah perubahan. Di satu sisi, penghitung ini mungkin meluap, tetapi di sisi lain, prosesor x86_64 modern mendukung operasi CAS 128-bit. Yaitu ketika membandingkan pointer ke penghitung, Anda dapat memberikan hingga 64 bit, dan seseorang memperkirakan bahwa ini cukup untuk operasi algoritma yang berkelanjutan selama 10 tahun.
  3. Beberapa arsitektur (ARM, misalnya) menyediakan instruksi LL / SC (load linked, store conditional) yang tidak hanya memungkinkan Anda untuk mendapatkan nilai alamat saat ini dalam memori, tetapi juga untuk memahami apakah nilai ini telah berubah sejak pembacaan terakhir.

Untuk menggunakan struktur data seperti tumpukan, daftar, atau antrian, yang bebas dari penguncian, secara umum, di mana ada risiko tetap dengan pointer menggantung ke node jarak jauh, ada seluruh keluarga solusi untuk masalah ABA berdasarkan pada penghapusan node yang ditangguhkan. Ini termasuk pengumpul sampah, penunjuk bahaya dan mekanisme baca-modifikasi-tulis (lihat RCU ).

Baca lebih lanjut: satu (Rusia) , dua (Inggris) , tiga (Inggris)

FAA


Ambil dan Tambah. Ahem ... dapatkan dan tambahkan (sepertinya konsep ini tidak pernah diterjemahkan ke dalam bahasa Rusia). Operasi atom dengan dua argumen: variabel atom atau alamat di memori, dan nilai yang harus diubah oleh variabel ini. Jika arsitektur memungkinkan, operasi mengembalikan nilai sebelumnya dari variabel yang diubah (x86 memungkinkan sejak i486). Tidak seperti CAS , FAA selalu berhasil.

Kode palsu
 int faa(int* addr, int diff) { int value = *addr; *addr = value + diff; return value; } 

Dalam C ++, ini diimplementasikan sebagai keluarga metode std::atomic<T>::fetch_add , fetch_sub , fetch_and , fetch_or , fetch_xor dan fungsi bebas yang sesuai std::atomic_fetch_add , dll.

Sesuai instruksi atom, FAA digunakan dalam implementasi primitif sinkronisasi dan algoritma kunci-bebas dan struktur data.

Baca lebih lanjut: sekali (Rusia) , dua (Inggris)

RCU


Baca-Salin-Perbarui. Baca-modifikasi-tulis. Ini adalah mekanisme non-pemblokiran untuk menyinkronkan akses ke struktur data (tentu saja bebas-penguncian). Ini digunakan dalam kasus di mana kecepatan membaca sangat penting. Ini adalah contoh dari tradeoff waktu dan memori (space-time tradeoff).

Gagasan RCU adalah bahwa aliran penulis tidak mengubah data di tempat, tetapi membuat salinan, membuat perubahan yang diperlukan di dalamnya dan secara atomis menukar data saat ini dan salinan yang diubah. Pada saat yang sama, utas pembaca terus-menerus memiliki akses ke data - lama atau baru, siapa pun yang punya waktu. Ketika tidak ada pembaca yang tersisa bekerja dengan versi yang sudah ketinggalan zaman, penulis menghapus data yang tidak lagi diperlukan, membebaskan memori.

RCU yang sangat disederhanakan berfungsi seperti ini:

  • Banyak pembaca, satu penulis.
  • Membaca dan mengubah terjadi secara bersamaan.
  • Pembaca menggunakan sinkronisasi yang sangat ringan. Bahkan, pembaca hanya perlu memberi tahu penulis pada saat memasuki bagian kritis dan pada saat meninggalkannya. Bekerja dengan data yang disinkronkan hanya terjadi di bagian kritis.
  • Penulis, segera setelah secara atomik mengganti data dengan salinan, mengumumkan permulaan dari apa yang disebut periode rahmat (grace period). Masa tenggang berakhir ketika semua pembaca yang berada di bagian kritis pada awal periode ini meninggalkan bagian kritis mereka. Sekarang penulis dapat dengan aman menghapus data yang sudah usang. Tersirat bahwa semua bagian kritis terbatas, yang menjamin terbatasnya masa tenggang.

RCU sangat bagus untuk data yang sering dibaca dan jarang diperbarui. Mekanisme ini secara aktif digunakan dalam kernel Linux, di mana cukup mudah untuk menentukan kapan masa tenggang berakhir.

Kekurangan:

  • Buruk untuk menyinkronkan akses ke data yang sering diubah.
  • Sulit diimplementasikan di ruang pengguna.
  • Tergantung pada kemampuan untuk mengubah pointer secara atom ke alamat dalam memori, tetapi tidak semua arsitektur menyediakan kemampuan ini.

Baca lebih lanjut: sekali (Rusia) , dua (Inggris)

Penyimpanan data


ASAM


Atomicity, Konsistensi, Isolasi, Daya Tahan. Atomicity, konsistensi, isolasi, daya tahan. Ini adalah seperangkat persyaratan transaksi dalam DBMS. ACID menyediakan operasi DBMS yang andal dan dapat diprediksi bahkan jika terjadi kesalahan.

  • Atomicity memastikan bahwa transaksi selesai atau tidak melakukan apa-apa. Keadaan perantara tidak mungkin, tidak akan seperti satu operasi transaksi berhasil, dan yang lainnya tidak. Semua atau tidak sama sekali.
  • Konsistensi memastikan bahwa semua data dalam database memenuhi semua aturan dan batasan yang ditentukan baik sebelum dimulainya transaksi dan setelah penyelesaiannya. Selama pelaksanaan transaksi, konsistensi dapat dilanggar.
  • Isolasi memastikan transaksi bersamaan tidak saling mempengaruhi. Tidak ada transaksi yang memiliki akses ke data tidak konsisten yang diproses oleh transaksi lain.
  • Daya tahan berarti bahwa hasil transaksi yang berhasil disimpan dalam database dan tidak dapat hilang, tidak peduli apa yang terjadi pada database segera setelah transaksi selesai.

Semua DBMS relasional utama sepenuhnya mendukung ACID . Di dunia NoSQL, dukungan penuh seperti itu kemungkinan besar merupakan pengecualian.

Baca lebih lanjut: satu kali (bahasa Inggris) , dua (bahasa Inggris)

Cap


Teorema CAP. Teorema CAP. Teorema menyatakan bahwa setiap sistem terdistribusi dapat memiliki tidak lebih dari dua properti dari daftar: konsistensi data ( Konsistensi ), ketersediaan ( Ketersediaan ), ketahanan terhadap pemisahan ( Toleransi partisi ).

  • Konsistensi dalam hal ini berarti konsistensi konsisten (disederhanakan). Yaitu segera setelah operasi pembaruan data pada satu node selesai dengan sukses, semua node lain sudah memiliki data yang diperbarui ini. Dengan demikian, semua node dalam keadaan konsisten. Ini bukan konsistensi yang disyaratkan oleh ACID .
  • Ketersediaan berarti bahwa setiap simpul yang gagal mengembalikan jawaban yang benar untuk setiap permintaan (baik untuk membaca dan menulis) dalam jumlah waktu yang wajar. Tidak ada jaminan bahwa tanggapan dari node yang berbeda cocok.
  • Perlawanan terhadap pemisahan berarti bahwa sistem akan terus bekerja dengan benar jika terjadi kehilangan jumlah pesan yang sewenang-wenang di antara simpul-simpulnya.

Karena ketiga sifat tidak dapat dicapai, dari sudut pandang teorema CAP , semua sistem terdistribusi jatuh ke dalam tiga kelas: CA , CP, dan AP . Sistem CA jelas tidak memiliki resistensi pemisahan. Karena dalam sebagian besar kasus, distribusi menyiratkan distribusi melalui jaringan nyata, dan dalam jaringan nyata selalu ada probabilitas nol untuk kehilangan suatu paket, maka sistem CA kurang menarik.

Pilihannya adalah antara CP dan AP , yaitu antara konsistensi dan ketersediaan. DBMS relasional tradisional yang mengikuti prinsip ACID lebih memilih konsistensi. Sementara banyak solusi NoSQL memilih aksesibilitas dan BASE .

Dalam kasus operasi normal jaringan, yaitu, ketika tidak ada pemisahan jaringan, teorema CAP tidak memaksakan pembatasan pada konsistensi dan ketersediaan. Yaitu menyumbangkan sesuatu tidak perlu.

Baca lebih lanjut: satu (Rusia) , dua (Inggris) , tiga (Inggris)

Pacelc


Teorema PACELC. Teorema PACELC. Ini adalah perpanjangan dari teorema CAP , yang menyatakan bahwa sistem terdistribusi dalam kasus Pemisahan terpaksa memilih antara Ketersediaan dan Konsistensi , dan dalam kasus operasi jaringan normal ( Lain ), Anda harus memilih antara Latensi dan Konsistensi )

Dengan demikian, jika teorema CAP membedakan 2 kelas sistem yang stabil dengan pemisahan jaringan, maka PACELC memiliki 4 di antaranya: PA / EL , PA / EC , PC / EL dan PC / EC . Beberapa database NoSQL dapat mengubah kelas mereka tergantung pada pengaturan.

Baca lebih lanjut: sekali (Rusia) , dua (Inggris)

DASAR


Pada dasarnya Tersedia, Status lunak, Konsistensi akhirnya. Ketersediaan dasar, kondisi rapuh, konsistensi dalam jangka panjang. Menurut teorema CAP dalam sistem terdistribusi, sesuatu harus ditinggalkan. Koherensi yang ketat biasanya ditinggalkan demi koherensi dalam jangka panjang. Yang berarti bahwa dengan tidak adanya perubahan data, suatu hari sistem akan pada akhirnya mencapai kondisi yang konsisten.

Untuk menunjukkan kompromi seperti itu, BASE singkatan mulai digunakan agak erat , dan permainan istilah kimia ternyata ( ACID - keasaman, BASE - kebasaan).

  • Pada dasarnya Tersedia berarti bahwa sistem menjamin ketersediaan data, itu menanggapi setiap permintaan. Tetapi jawabannya mungkin data yang lama atau tidak konsisten (atau tidak ada)
  • Status lunak berarti keadaan sistem dapat berubah seiring waktu meskipun tidak ada permintaan untuk perubahan data. Karena pada titik waktu mana pun, data dapat dibawa ke keadaan konsisten.
  • Konsistensi akhirnya berarti bahwa jika data berhenti berubah, mereka tentu saja akan berakhir dalam keadaan yang konsisten. Yaitu permintaan yang sama untuk node yang berbeda akan menghasilkan jawaban yang sama.

Baca lebih lanjut: satu kali (bahasa Inggris) , dua (bahasa Inggris)

Prinsip Pengembangan Perangkat Lunak


KERING


Jangan Ulangi Diri Anda Sendiri. Jangan diulang. Ini adalah prinsip pengembangan perangkat lunak, ide utamanya adalah untuk mengurangi jumlah informasi yang digandakan dalam sistem, dan tujuannya adalah untuk mengurangi kompleksitas sistem dan meningkatkan pengelolaannya.

Dalam buku aslinya ( The Pragmatic Programmer book, oleh Andrew Hunt dan David Thomas ), prinsip ini dirumuskan sebagai berikut: "Setiap pengetahuan harus memiliki representasi tunggal, konsisten, dan otoritatif dalam sistem." Dalam hal ini, pengetahuan dipahami sebagai bagian dari area subjek atau algoritma: kode, skema database, protokol interaksi tertentu, dll. Dengan demikian, untuk membuat satu perubahan pada sistem, hanya satu "pengetahuan" yang perlu diperbarui di satu tempat.

Contoh bodoh: klien dan server mengirimkan data terstruktur satu sama lain. Karena ini adalah aplikasi yang berbeda yang berjalan pada mesin yang berbeda, maka mereka berdua harus memiliki implementasi sendiri dari struktur ini. Jika sesuatu berubah, perubahan harus dilakukan di dua tempat. Langkah yang jelas untuk menghindari pengulangan ini adalah mengalokasikan kode umum ke pustaka yang terpisah. Langkah selanjutnya adalah membuatnya sesuai dengan deskripsi struktur (Google Protokol Buffer, misalnya), agar tidak menulis jenis kode yang sama untuk mengakses bidang struktur.

Duplikasi kode hanyalah kasus khusus pelanggaran KERING . Dan itu tidak selalu terjadi. Jika dua potong kode terlihat sama, tetapi masing-masing menerapkan logika bisnis mereka sendiri, KERING tidak rusak.

Seperti prinsip lainnya, KERING adalah alat, bukan dogma. Semakin besar sistem, semakin mudah melanggar prinsip ini. Pertama, cita-cita itu tidak mungkin tercapai. Dan kedua, jika secara membabi buta mengikuti KERING mengarah ke kode yang lebih rumit dan membuatnya lebih sulit untuk dipahami, maka lebih baik untuk meninggalkannya.

Baca lebih lanjut: satu (Rusia) , dua (Rusia)

CIUMAN


Tetap Sederhana, Bodoh. Buat lebih mudah (bodoh dalam hal ini bukan panggilan). Ini adalah prinsip desain yang sebagian besar sistem bekerja lebih baik jika tetap sederhana. Prinsipnya berasal dari industri pesawat terbang dan banyak diterapkan di mana, termasuk dalam pengembangan perangkat lunak.

Dalam kasus terakhir, KISS berguna baik dalam mendesain dan menulis kode secara langsung. Arsitektur dan kode sederhana tidak hanya lebih mudah dipahami, tetapi juga lebih mudah digunakan, dipelihara, dan dikembangkan. MapReduce tidak boleh dibodohi jika pasangan produsen-konsumen sudah cukup. Keajaiban metaprogramming sangat rumit jika Anda dapat melakukannya dengan beberapa fungsi biasa dan mencapai tingkat kinerja yang diperlukan.

Dengan semua ini, orang tidak boleh lupa bahwa kesederhanaan bukanlah tujuan, tetapi hanya persyaratan non-fungsional. Hal utama adalah untuk mencapai tujuan desain / implementasi, dan disarankan untuk melakukan ini dengan cara sesederhana mungkin.

Baca lebih lanjut: satu (Rusia) , dua (Rusia) , tiga (Inggris)

YAGNI


Anda Tidak Akan Membutuhkannya. Anda tidak membutuhkannya. Ini adalah prinsip pengembangan perangkat lunak, gagasan utamanya adalah penolakan fungsi yang berlebihan, dan tujuannya adalah untuk menghemat sumber daya yang dihabiskan untuk pengembangan.

YAGNI mengatakan bahwa Anda tidak perlu merancang atau mengimplementasikan fungsi yang tidak dibutuhkan saat ini. Bahkan jika Anda yakin mereka akan dibutuhkan di masa depan. Tidak perlu menambahkan abstraksi yang tidak perlu, manfaatnya akan muncul beberapa saat kemudian.

Masalahnya adalah orang tidak memprediksi masa depan dengan baik. Oleh karena itu, kemungkinan besar semua yang dilakukan "cadangan" tidak akan berguna. Dan ternyata waktu dan uang yang dihabiskan untuk pengembangan, pengujian, dan dokumentasi seperti itu terbuang sia-sia. Plus, perangkat lunak menjadi lebih rumit, sumber daya tambahan harus dihabiskan untuk mendukungnya lagi. Lebih buruk lagi, ketika ternyata perlu dilakukan secara berbeda. Uang dan waktu akan dihabiskan juga untuk koreksi.

Prinsip YAGNI agak lebih radikal daripada KERING dan CIUMAN . Jika mereka memecah sistem menjadi bagian-bagian yang dapat dipahami dan membuat keputusan sederhana, maka YAGNI hanya memotong bagian dan solusi yang tidak perlu.

Baca lebih lanjut: satu (Rusia) , dua (Inggris) , tiga (Inggris)

Nih


Tidak Diciptakan Di Sini. Tidak ditemukan di sini. Ini adalah sindrom penolakan terhadap perkembangan orang lain, suatu posisi yang secara praktis berbatasan dengan penemuan sepeda. Seringkali, sindrom disertai dengan keyakinan bahwa menciptakan teknologi di dalam perusahaan akan lebih cepat dan lebih murah, dan teknologi itu sendiri akan lebih memenuhi kebutuhan perusahaan. Namun, dalam kebanyakan kasus ini bukan itu masalahnya, dan NIH adalah anti-pola.

Berikut adalah beberapa kasus yang membenarkan NIH :

  • Kualitas solusi pihak ketiga tidak cukup tinggi, atau harganya tidak cukup rendah.
  • Solusi pihak ketiga memiliki batasan lisensi.
  • Menggunakan solusi pihak ketiga menciptakan ketergantungan pada pemasoknya dan dengan demikian mengancam bisnis.

Baca lebih lanjut: satu (Rusia) , dua (Inggris) , tiga (Inggris)

Ftse


Teorema Dasar Rekayasa Perangkat Lunak. Teorema dasar pengembangan perangkat lunak. Sebenarnya, ini bukan teorema, tidak punya bukti. Ini adalah perkataan terkenal oleh Andrew Koenig:
Masalah apa pun dapat diselesaikan dengan menambahkan lapisan abstraksi lainnya.
Terkadang mereka menambah frasa ini "... kecuali untuk masalah terlalu banyak lapisan abstraksi." Secara umum, "teorema" bukanlah hal yang serius, tetapi perlu diketahui tentang hal itu.

Baca lebih lanjut: satu kali (bahasa Inggris) , dua (bahasa Inggris)

GRASP


Pola Perangkat Lunak Penugasan Tanggung Jawab Umum. Template alokasi tanggung jawab umum. Sembilan pola ini dirumuskan dalam Menerapkan UML dan Pola oleh Craig Larman . Setiap template adalah solusi khas untuk satu (tetapi lebih umum) masalah desain perangkat lunak.

  1. Ahli Informasi . Masalah: apa prinsip umum pembagian tanggung jawab antara objek? Keputusan: memberikan tugas kepada seseorang yang memiliki informasi yang diperlukan untuk memenuhi kewajiban ini.
  2. Pencipta Masalah: siapa yang harus bertanggung jawab untuk membuat objek baru? Solusi: kelas B harus membuat instance kelas A jika satu atau lebih kondisi berikut ini benar:
    - kelas B agregat atau berisi instance A
    - B menulis A
    - B aktif menggunakan A
    - B memiliki data inisialisasi A
  3. Kopling rendah Masalah: bagaimana cara mengurangi dampak perubahan? Bagaimana cara meningkatkan kemungkinan penggunaan kembali? Solusi: sebarkan tanggung jawab sehingga konektivitas rendah. Kopling adalah ukuran seberapa kaku elemen-elemen terhubung, seberapa besar mereka bergantung satu sama lain. Yaitu Disarankan untuk menghubungkan objek sehingga mereka tahu tentang satu sama lain hanya minimum yang diperlukan.
  4. Gearing tinggi ( Kohesi Tinggi ). Masalah: Bagaimana cara saya mengelola kompleksitas? Solusi: sebarkan tanggung jawab agar keterlibatan tinggi tetap terjaga. Keterlibatan tinggi berarti bahwa tanggung jawab satu elemen difokuskan pada satu bidang.
  5. Pengendali Masalah: siapa yang harus bertanggung jawab untuk menangani acara masukan? Solusi: tentukan kelas sebagai penanggung jawab, yang mewakili seluruh sistem atau subsistem sebagai keseluruhan (pengontrol eksternal), atau satu skrip khusus (skrip atau pengontrol sesi). Pada saat yang sama, pengontrol tidak menerapkan reaksi terhadap peristiwa, melainkan mendelegasikan ini ke pelaksana yang relevan.
  6. Polimorfisme ( Polimorfisme ). Masalah: bagaimana cara menangani berbagai perilaku berdasarkan jenis? : , , , .
  7. ( Pure Fabrication ). : , ? : , .
  8. ( Indirection ). : , Low Coupling ? : .
  9. Resistensi terhadap perubahan ( Variasi yang Dilindungi ). Masalah: bagaimana merancang objek dan subsistem sehingga perubahan di dalamnya tidak memiliki efek yang tidak diinginkan pada elemen lain? Solusi: temukan kemungkinan titik ketidakstabilan dan buat antarmuka yang stabil di sekitarnya, berkomunikasi hanya melalui antarmuka semacam itu.

Pola GRASP secara konstan berpotongan dengan pola Gang Four dan prinsip SOLID . Ini normal, karena mereka semua memecahkan masalah umum - untuk menyederhanakan pembuatan perangkat lunak berkualitas tinggi.

Baca lebih lanjut: satu (Rusia) , dua (Inggris) , tiga (Rusia)

PADAT


Prinsip-prinsip SOLID. Ini adalah lima prinsip pemrograman dan desain berorientasi objek (singkatannya dibuat dari huruf pertama namanya). Mendapatkan ketenaran berkat Robert Martin pada awal 2000-an. Tujuan utama dari prinsip-prinsip ini adalah menciptakan perangkat lunak yang mudah dipahami, dipelihara, dan dikembangkan.

  1. Prinsip tanggung jawab tunggal ( single Prinsip Tanggung Jawab, SRP ). Kelas atau modul seharusnya hanya memiliki satu tanggung jawab. "Lakukan hanya satu hal, tetapi lakukan dengan baik."
  2. / ( Open Closed Principle, OCP ). (, , ) , . : , .
  3. ( Liskov Substitution Principle, LSP ). , . Yaitu - .
  4. ( Interface Segregation Principle, ISP ). , . , . , , . , .
  5. Ketergantungan Inversi Prinsip ( dari ketergantungan Pembalikan Prinsip, DIP ). Modul tingkat atas tidak harus bergantung pada modul tingkat bawah. Semua modul harus bergantung pada abstraksi. Abstraksi tidak harus bergantung pada detail. Rinciannya harus bergantung pada abstraksi. Sebagai contoh, baik antarmuka maupun kelas konkret tidak boleh mengandung atau menerima kelas konkret lainnya sebagai argumen dari metode mereka, tetapi hanya antarmuka (dalam arti Java dan C #).

Baca lebih lanjut: satu (Rusia) , dua (Inggris) , tiga (Inggris)

Lainnya


Abi


Antarmuka Biner Aplikasi. Antarmuka aplikasi biner. Ini adalah seperangkat konvensi yang mendefinisikan interaksi modul biner (file yang dapat dieksekusi, perpustakaan, OS). Dua modul harus dibuat sesuai dengan satu ABI - ini adalah prasyarat untuk kompatibilitas biner mereka, dalam hal ini mereka dapat berinteraksi tanpa masalah (misalnya, file yang dapat dieksekusi dihubungkan ke perpustakaan dan dieksekusi oleh sistem operasi).

Contoh ABI adalah format file yang dapat dieksekusi ELF di Linux dan PE pada Windows. Setiap OS mengharapkan bahwa data yang diperlukan (sumber daya, titik masuk, dll.) Terletak di file biner sesuai dengan format yang sesuai. Jelas, ELF dan PE berbeda, karena program Linux tidak berjalan langsung di Windows dan sebaliknya.

Pada tingkat library dan executable, ABI dapat menentukan penempatan bidang dalam suatu kelas, kelas dasar dalam turunan, mekanisme untuk mengimplementasikan fungsi virtual, format frame panggilan stack, aturan untuk meneruskan argumen ke fungsi yang dipanggil, dll., Dll.

C ++ tidak memiliki satu pun ABI standar , yang tidak mengherankan, karena itu tergantung pada arsitektur dan OS. Sebagai contoh, kompiler C ++ untuk banyak sistem operasi mirip Unix (Linux, FreeBSD, MacOS) pada x86_64 ikuti System V AMD64 ABI , pada ARM - ARM C ++ ABI . Visual C ++ ABI tidak dipublikasikan secara resmi, tetapi setidaknya sebagian direkayasa ulang. Sangat berbeda dari System V ABI, mereka memiliki aturan yang sama sekali berbeda untuk menyembunyikan nama (mangling) danmeneruskan argumen ke fungsi yang dipanggil (Linux menggunakan 6 register, Windows menggunakan 4 register), dan banyak perbedaan lainnya.

Bahkan jika API dan ABI tetap sama, dan hanya detail implementasi yang berubah, kompatibilitas biner mungkin rusak . Misalnya, dalam C ++ 11, ada persyaratan untuk string untuk menyimpan karakter secara berurutan (seperti dalam vektor). Karena itu, GCC 5 harus mengubah implementasi string ( SAP digunakan sebelumnya ), yang menyebabkan ketidakcocokan biner.

Baca lebih lanjut: sekali (Rusia) , dua (Inggris) dan semua tautan dari dua paragraf sebelumnya.

Sapi


Salin Saat Menulis. Salin saat merekam. Ini adalah mekanisme manajemen sumber daya, juga dikenal sebagai berbagi implisit dan salinan malas. Idenya adalah bahwa ketika salinan diperlukan, sumber daya tidak benar-benar disalin, tetapi tautan ke sana dibuat. Dan hanya ketika ada permintaan untuk perubahan - dalam aslinya atau di "copy" - hanya pada saat pembuatan salinan lengkap terjadi.

Keuntungan dari SAP jelas: menyalin objek apa pun terjadi secara instan. Jika objek sering disalin tetapi jarang berubah, peningkatan kinerja bisa signifikan.

Contoh penggunaan COW :

  • Manajemen memori proses virtual di Linux. Ketika fork()halaman dipanggil , memori proses tidak disalin, tetapi hanya ditandai sebagai dibagikan.
  • Snapshots di beberapa sistem file (Btrfs, ZFS) dan database (MS SQL Server).
  • Sebelum C ++ 11, beberapa implementasi std::stringmenggunakan SAP . Dalam C ++ 11, persyaratan untuk std::stringtelah berubah (lihat ABI ).
  • Banyak jenis dalam Qt menggunakan SAP .

Baca lebih lanjut: satu kali (bahasa Inggris) , dua (bahasa Inggris)

FBC, FBCP


Kelas Dasar Rapuh (Masalah). Masalah kelas dasar yang rapuh. Ini adalah masalah OOP mendasar, intinya adalah bahwa perubahan kelas dasar yang benar dapat menyebabkan kesalahan pada salah satu ahli waris.

Misalnya, untuk rekursi yang tak terbatas
 struct Base { virtual void method1() { // ... } virtual void method2() { // ... method1(); // <--      } }; struct Derived : Base { void method1() override { method2(); } }; 

Anda dapat memecahkan masalah FBC hanya dengan meninggalkan pewarisan yang mendukung komposisi, misalnya, atau memperluas antarmuka dalam terminologi Java (dalam C ++, ini akan mewarisi hanya untuk kelas dasar abstrak tanpa implementasi negara dan metode). Dalam kasus lain, Anda hanya dapat mencoba meminimalkan kemungkinan FBCP dengan tips berikut:

  • Larang pewarisan atau pendefinisian ulang di tempat yang tidak diperlukan (kata kunci finaldalam C ++ dan Java).
  • Ahli waris tidak boleh memiliki akses ke interior kelas dasar, komunikasi hanya dapat melalui antarmuka publik.
  • Metode pewaris hanya dapat memanggil metode virtual yang dipanggil dalam metode redefined dari kelas dasar, dan metode redefined itu sendiri.

Baca lebih lanjut: satu (Inggris) , dua (Inggris) , tiga (Inggris)

LRU


Paling Baru Digunakan. Ekstrusi sudah lama tidak digunakan. Ini adalah salah satu algoritma caching (mereka juga kebijakan preemptive). Secara umum, cache dapat dianggap sebagai penyimpanan cepat pasangan nilai kunci, salah satu karakteristik utamanya adalah rasio hit. Semakin tinggi level ini, semakin sering nilai yang diinginkan ada di cache cepat dan semakin jarang itu harus dicari dalam penyimpanan lambat. Tetapi karena memori tidak pernah kenyal, ukuran cache harus dibatasi. Tugas algoritma caching adalah menentukan elemen mana yang harus dibuang dari cache yang diisi, jika perlu, untuk memaksimalkan tingkat hit.

LRUmenggantikan elemen cache mereka, yang tidak ada yang mengakses paling lama. Ini mungkin adalah algoritma caching yang paling terkenal. Mungkin karena kombinasi efisiensi dan kesederhanaan. Konsumsi memori LRU adalah O (n), waktu akses rata-rata ke nilai adalah O (1), waktu rata-rata untuk menambahkan elemen juga O (1). Untuk implementasi, tabel hash dan daftar tertaut ganda biasanya digunakan.

Misalnya saja
 template <class K, class V> class LRU { private: using Queue = std::list<std::pair<K, V>>; using Iterator = typename Queue::iterator; using Hash = std::unordered_map<K, Iterator>; Queue queue_; Hash hash_; const size_t limit_; public: LRU(size_t limit) : limit_(limit) { } std::optional<V> get(const K& key) { const auto it = hash_.find(key); if (it == hash_.end()) { return {}; } it->second = reorder(it->second); return { it->second->second }; } void add(K&& key, V&& value) { if (hash_.size() >= limit_) { pop(); } queue_.emplace_front(std::move(key), std::move(value)); const auto it = queue_.begin(); hash_[it->first] = it; } private: Iterator reorder(Iterator it) { queue_.emplace_front(std::move(it->first), std::move(it->second)); queue_.erase(it); return queue_.begin(); } void pop() { hash_.erase(queue_.back().first); queue_.pop_back(); } }; 

Kelemahan yang jelas dari LRU adalah konsumsi memori yang tinggi, karena menggunakan dua struktur elemen n masing-masing. Selain LRU, ada banyak algoritma caching lainnya untuk berbagai kasus: MRU (Paling Baru Digunakan), LFU (Paling Sering Digunakan), LRU Tersegmentasi, 2Q, dll.

Baca lagi: satu kali (Inggris) , dua (Rusia) , tiga

PS


Jika saya melewatkan sesuatu atau keliru di suatu tempat - tulis di komentar.

Source: https://habr.com/ru/post/id470317/


All Articles