Rumah > hujung hadapan web > tutorial js > Mencuci kod anda: jangan buat saya berfikir

Mencuci kod anda: jangan buat saya berfikir

Barbara Streisand
Lepaskan: 2024-12-06 14:54:13
asal
374 orang telah melayarinya

Washing your code: don’t make me think

Anda sedang membaca petikan daripada buku saya tentang kod bersih, "Mencuci kod anda." Tersedia sebagai PDF, EPUB dan sebagai edisi paperback dan Kindle. Dapatkan salinan anda sekarang.


Kod pintar ialah sesuatu yang mungkin kita lihat dalam soalan temu duga kerja atau kuiz bahasa, apabila mereka mengharapkan kita mengetahui cara ciri bahasa, yang mungkin tidak pernah kita lihat sebelum ini, berfungsi. Jawapan saya kepada semua soalan ini ialah: "ia tidak akan lulus semakan kod".

Sesetengah orang mengelirukan ringkas dengan kejelasan. Kod pendek (ringkas) tidak selalunya kod yang paling jelas (kejelasan), selalunya ia adalah sebaliknya. Berusaha untuk menjadikan kod anda lebih pendek ialah matlamat yang mulia, tetapi ia tidak sepatutnya mengorbankan kebolehbacaan.

Terdapat banyak cara untuk menyatakan idea yang sama dalam kod, dan ada yang lebih mudah difahami daripada yang lain. Kami harus sentiasa menyasarkan untuk mengurangkan beban kognitif pembangun seterusnya yang membaca kod kami. Setiap kali kita terjumpa sesuatu yang tidak jelas, kita membazirkan sumber otak kita.

Maklumat: Saya "mencuri" nama bab ini daripada buku Steve Krug tentang kebolehgunaan web dengan nama yang sama.

Corak gelap JavaScript

Mari kita lihat beberapa contoh. Cuba tutup jawapan dan teka apa yang coretan kod ini lakukan. Kemudian, hitung jumlah yang anda teka dengan betul.

Contoh 1:

const percent = 5;
const percentString = percent.toString().concat('%');
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Kod ini hanya menambah tanda % pada nombor dan harus ditulis semula sebagai:

const percent = 5;
const percentString = `${percent}%`;
// → '5%'
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Contoh 2:

const url = 'index.html?id=5';
if (~url.indexOf('id')) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Simbol ~ dipanggil pengendali bitwise NOT. Kesan bergunanya di sini ialah ia mengembalikan nilai palsu hanya apabila indexOf() mengembalikan -1. Kod ini hendaklah ditulis semula sebagai:

const url = 'index.html?id=5';
if (url.includes('id')) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Contoh 3:

const value = ~~3.14;
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Satu lagi penggunaan operator NOT yang tidak jelas adalah untuk membuang bahagian pecahan nombor. Gunakan Math.floor() sebaliknya:

const value = Math.floor(3.14);
// → 3
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Contoh 4:

if (dogs.length + cats.length > 0) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Yang ini boleh difahami selepas seketika: ia menyemak sama ada salah satu daripada dua tatasusunan mempunyai sebarang elemen. Walau bagaimanapun, adalah lebih baik untuk menjadikannya lebih jelas:

if (dogs.length > 0 && cats.length > 0) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Contoh 5:

const header = 'filename="pizza.rar"';
const filename = header.split('filename=')[1].slice(1, -1);
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Yang ini mengambil sedikit masa untuk saya faham. Bayangkan kita mempunyai sebahagian daripada URL, seperti nama fail="pizza". Mula-mula, kita bahagikan rentetan dengan = dan ambil bahagian kedua, "pizza". Kemudian, kita potong watak pertama dan terakhir untuk mendapatkan piza.

Saya mungkin akan menggunakan ungkapan biasa di sini:

const header = 'filename="pizza.rar"';
const filename = header.match(/filename="(.*?)"/)[1];
// → 'pizza'
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Atau, lebih baik lagi, URLSearchParams API:

const header = 'filename="pizza.rar"';
const filename = new URLSearchParams(header)
  .get('filename')
  .replaceAll(/^"|"$/g, '');
// → 'pizza'
Salin selepas log masuk
Salin selepas log masuk

Petikan ini pelik. Biasanya kami tidak memerlukan petikan mengenai parameter URL, jadi bercakap dengan pembangun bahagian belakang boleh menjadi idea yang baik.

Contoh 6:

const percent = 5;
const percentString = percent.toString().concat('%');
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Dalam kod di atas, kami menambah harta pada objek apabila syarat itu benar, jika tidak, kami tidak melakukan apa-apa. Niatnya lebih jelas apabila kita mentakrifkan secara eksplisit objek untuk dimusnahkan daripada bergantung pada pemusnahan nilai palsu:

const percent = 5;
const percentString = `${percent}%`;
// → '5%'
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Saya biasanya lebih suka apabila objek tidak berubah bentuk, jadi saya akan mengalihkan keadaan di dalam medan nilai:

const url = 'index.html?id=5';
if (~url.indexOf('id')) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Contoh 7:

const url = 'index.html?id=5';
if (url.includes('id')) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Satu pelapik yang indah ini mencipta tatasusunan yang diisi dengan nombor dari 0 hingga 9. Tatasusunan(10) mencipta tatasusunan dengan 10 elemen kosong, kemudian kaedah kekunci() mengembalikan kekunci (nombor dari 0 hingga 9) sebagai lelaran, yang kemudiannya kita tukar menjadi tatasusunan biasa menggunakan sintaks penyebaran. Emoji kepala meletup…

Kita boleh menulis semula menggunakan gelung for:

const value = ~~3.14;
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Walaupun saya suka mengelakkan gelung dalam kod saya, versi gelung lebih mudah dibaca untuk saya.

Suatu tempat di tengah akan menggunakan kaedah Array.from():

const value = Math.floor(3.14);
// → 3
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Array.from({length: 10}) mencipta tatasusunan dengan 10 elemen undefined, kemudian menggunakan kaedah map(), kami mengisi tatasusunan dengan nombor dari 0 hingga 9.

Kita boleh menulisnya dengan lebih pendek dengan menggunakan panggilan balik peta Array.from():

if (dogs.length + cats.length > 0) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Peta eksplisit() lebih mudah dibaca dan kita tidak perlu mengingati perkara yang dilakukan oleh hujah kedua Array.from(). Selain itu, Array.from({length: 10}) lebih mudah dibaca daripada Array(10). Walaupun hanya sedikit.

Jadi, apakah markah anda? Saya rasa saya kira-kira 3/7.

Kawasan kelabu

Sesetengah corak berada di antara kepandaian dan kebolehbacaan.

Contohnya, menggunakan Boolean untuk menapis elemen tatasusunan palsu (null dan 0 dalam contoh ini):

if (dogs.length > 0 && cats.length > 0) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Saya dapati corak ini boleh diterima; walaupun ia memerlukan pembelajaran, ia lebih baik daripada alternatif:

const header = 'filename="pizza.rar"';
const filename = header.split('filename=')[1].slice(1, -1);
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Walau bagaimanapun, perlu diingat bahawa kedua-dua variasi menapis nilai palsu, jadi jika sifar atau rentetan kosong adalah penting, kita perlu menapis secara eksplisit untuk undefined atau null:

const header = 'filename="pizza.rar"';
const filename = header.match(/filename="(.*?)"/)[1];
// → 'pizza'
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Jadikan perbezaan dalam kod jelas

Apabila saya melihat dua baris kod rumit yang kelihatan sama, saya menganggap ia berbeza dalam beberapa cara, tetapi saya belum nampak perbezaannya lagi. Jika tidak, pengaturcara mungkin akan mencipta pembolehubah atau fungsi untuk kod berulang dan bukannya menyalinnya.

Sebagai contoh, kami mempunyai kod yang menjana ID ujian untuk dua alatan berbeza yang kami gunakan pada projek, Enzim dan Codeception:

const header = 'filename="pizza.rar"';
const filename = new URLSearchParams(header)
  .get('filename')
  .replaceAll(/^"|"$/g, '');
// → 'pizza'
Salin selepas log masuk
Salin selepas log masuk

Sukar untuk segera mengesan sebarang perbezaan antara dua baris kod ini. Ingat pasangan gambar di mana anda perlu mencari sepuluh perbezaan? Itulah yang dilakukan oleh kod ini kepada pembaca.

Walaupun saya biasanya ragu-ragu tentang PENGERINGAN kod yang melampau, ini adalah kes yang baik untuknya.

Maklumat: Kami bercakap lebih lanjut tentang prinsip Jangan ulangi diri anda dalam bab Bahagikan dan takluk, atau gabung dan berehat.

const percent = 5;
const percentString = percent.toString().concat('%');
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Kini, tidak syak lagi bahawa kod untuk kedua-dua ID ujian adalah sama.

Mari kita lihat contoh yang lebih rumit. Katakan kita menggunakan konvensyen penamaan yang berbeza untuk setiap alat ujian:

const percent = 5;
const percentString = `${percent}%`;
// → '5%'
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Perbezaan antara dua baris kod ini sukar untuk diperhatikan dan kami tidak dapat memastikan bahawa pemisah nama (- atau _) adalah satu-satunya perbezaan di sini.

Dalam projek dengan keperluan sedemikian, corak ini mungkin akan muncul di banyak tempat. Satu cara untuk memperbaikinya ialah dengan mencipta fungsi yang menjana ID ujian untuk setiap alat:

const url = 'index.html?id=5';
if (~url.indexOf('id')) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Ini sudah jauh lebih baik, tetapi ia masih belum sempurna — kod berulang masih terlalu besar. Mari kita betulkan ini juga:

const url = 'index.html?id=5';
if (url.includes('id')) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Ini adalah kes ekstrem menggunakan fungsi kecil, dan saya biasanya cuba mengelakkan pemisahan kod sebanyak ini. Walau bagaimanapun, dalam kes ini, ia berfungsi dengan baik, terutamanya jika terdapat banyak tempat dalam projek di mana kita boleh menggunakan fungsi getTestIdProps() baharu.

Kadangkala, kod yang kelihatan hampir sama mempunyai perbezaan yang ketara:

const value = ~~3.14;
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Satu-satunya perbezaan di sini ialah parameter yang kami hantar ke fungsi dengan nama yang sangat panjang. Kita boleh mengalihkan keadaan di dalam panggilan fungsi:

const value = Math.floor(3.14);
// → 3
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Ini menghapuskan kod yang serupa, menjadikan keseluruhan coretan lebih pendek dan lebih mudah difahami.

Setiap kali kita menghadapi keadaan yang menjadikan kod berbeza sedikit, kita harus bertanya kepada diri sendiri: adakah syarat ini benar-benar perlu? Jika jawapannya "ya", kita harus bertanya kepada diri sendiri semula. Selalunya, tiada keperluan sebenar untuk keadaan tertentu. Sebagai contoh, mengapakah kita perlu menambah ID ujian untuk alatan yang berbeza secara berasingan? Tidak bolehkah kita mengkonfigurasi salah satu alat untuk menggunakan ID ujian yang lain? Jika kita menggali cukup dalam, kita mungkin mendapati tiada siapa yang tahu jawapannya, atau sebab asal tidak lagi relevan.

Pertimbangkan contoh ini:

if (dogs.length + cats.length > 0) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Kod ini mengendalikan dua kes tepi: apabila assetsDir tidak wujud dan apabila assetsDir bukan tatasusunan. Juga, kod penjanaan objek diduakan. (Dan jangan bercakap tentang ternaries bersarang…) Kita boleh menyingkirkan pendua dan sekurang-kurangnya satu syarat:

if (dogs.length > 0 && cats.length > 0) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Saya tidak suka kaedah castArray() Lodash yang tidak ditentukan dalam tatasusunan, yang bukan seperti yang saya jangkakan, tetapi hasilnya lebih mudah.

Elakkan jalan pintas

CSS mempunyai sifat trengkas dan pembangun sering menggunakannya secara berlebihan. Ideanya ialah satu sifat boleh menentukan berbilang sifat pada masa yang sama. Berikut ialah contoh yang baik:

const header = 'filename="pizza.rar"';
const filename = header.split('filename=')[1].slice(1, -1);
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Yang sama dengan:

const header = 'filename="pizza.rar"';
const filename = header.match(/filename="(.*?)"/)[1];
// → 'pizza'
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Satu baris kod dan bukannya empat, dan perkara yang berlaku masih jelas: kami menetapkan jidar yang sama pada keempat-empat sisi elemen.

Sekarang, lihat contoh ini:

const percent = 5;
const percentString = percent.toString().concat('%');
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Untuk memahami perkara yang mereka lakukan, kita perlu tahu bahawa:

  • apabila sifat margin mempunyai empat nilai, tertib adalah atas, kanan, bawah, kiri;
  • apabila ia mempunyai tiga nilai, tertib adalah atas, kiri/kanan, bawah;
  • dan apabila ia mempunyai dua nilai, tertib adalah atas/bawah, kiri/kanan.

Ini menghasilkan beban kognitif yang tidak perlu dan menjadikan kod lebih sukar untuk dibaca, diedit dan disemak. Saya mengelakkan trengkas seperti itu.

Isu lain dengan sifat trengkas ialah mereka boleh menetapkan nilai untuk sifat yang kami tidak mahu ubah. Pertimbangkan contoh ini:

const percent = 5;
const percentString = `${percent}%`;
// → '5%'
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Pengisytiharan ini menetapkan keluarga fon Helvetica, saiz fon 2rem dan menjadikan teks condong dan tebal. Apa yang kami tidak nampak di sini ialah ia turut menukar ketinggian garisan kepada nilai lalai biasa.

Peraturan saya ialah menggunakan sifat trengkas hanya apabila menetapkan nilai tunggal; jika tidak, saya lebih suka hartanah longhand.

Berikut ialah beberapa contoh yang baik:

const url = 'index.html?id=5';
if (~url.indexOf('id')) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Dan berikut ialah beberapa contoh yang perlu dielakkan:

const url = 'index.html?id=5';
if (url.includes('id')) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Walaupun sifat trengkas memang menjadikan kod lebih pendek, ia sering menjadikannya lebih sukar untuk dibaca, jadi gunakannya dengan berhati-hati.

Tulis kod selari

Menghapuskan keadaan tidak selalu mungkin. Walau bagaimanapun, terdapat cara untuk membuat perbezaan dalam cawangan kod lebih mudah dikesan. Salah satu pendekatan kegemaran saya ialah apa yang saya panggil pengekodan selari.

Pertimbangkan contoh ini:

const value = ~~3.14;
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Ia mungkin kesal peribadi, tetapi saya tidak suka apabila penyata pemulangan berada pada tahap yang berbeza, menjadikannya lebih sukar untuk dibandingkan. Mari tambahkan pernyataan lain untuk membetulkan perkara ini:

const value = Math.floor(3.14);
// → 3
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Kini, kedua-dua nilai pulangan berada pada tahap lekukan yang sama, menjadikannya lebih mudah untuk dibandingkan. Corak ini berfungsi apabila tiada satu pun cabang keadaan mengendalikan ralat, dalam hal ini pemulangan awal akan menjadi pendekatan yang lebih baik.

Maklumat: Kami bercakap tentang pulangan awal dalam bab Elakkan syarat.

Ini satu lagi contoh:

if (dogs.length + cats.length > 0) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Dalam contoh ini, kami mempunyai butang yang berkelakuan seperti pautan dalam penyemak imbas dan menunjukkan modal pengesahan dalam apl. Keadaan terbalik untuk prop onPress menjadikan logik ini sukar dilihat.

Mari jadikan kedua-dua keadaan positif:

if (dogs.length > 0 && cats.length > 0) {
  // Something fishy here…
}
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Kini, jelas bahawa kami sama ada menetapkan onPress atau prop pautan bergantung pada platform.

Kita boleh berhenti di sini atau melangkah lebih jauh, bergantung pada bilangan Platform.OS === keadaan 'web' dalam komponen atau berapa banyak prop yang perlu kita tetapkan secara bersyarat

Kita boleh mengekstrak prop bersyarat ke dalam pembolehubah berasingan:

const header = 'filename="pizza.rar"';
const filename = header.split('filename=')[1].slice(1, -1);
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Kemudian, gunakannya dan bukannya pengekodan keras keseluruhan keadaan setiap kali:

const header = 'filename="pizza.rar"';
const filename = header.match(/filename="(.*?)"/)[1];
// → 'pizza'
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk
Salin selepas log masuk

Saya juga mengalihkan prop sasaran ke cawangan web kerana ia tidak digunakan oleh apl lagi.


Semasa saya berumur dua puluhan, mengingati sesuatu tidak menjadi masalah bagi saya. Saya dapat mengingati buku yang pernah saya baca dan semua fungsi dalam projek yang sedang saya kerjakan. Sekarang saya berumur empat puluhan, itu tidak lagi berlaku. Saya kini menghargai kod mudah yang tidak menggunakan sebarang helah; Saya menghargai enjin carian, akses pantas kepada dokumentasi dan alatan yang membantu saya membuat alasan tentang kod dan menavigasi projek tanpa menyimpan segala-galanya dalam kepala saya.

Kita tidak sepatutnya menulis kod untuk diri kita sekarang tetapi untuk siapa kita akan menjadi beberapa tahun dari sekarang. Berfikir adalah sukar dan pengaturcaraan memerlukan banyak perkara, walaupun tanpa perlu mentafsir kod yang rumit atau tidak jelas.

Mula berfikir tentang:

  • Apabila anda berasa bijak dan menulis beberapa kod pendek dan bijak, fikirkan jika ada cara yang lebih mudah dan mudah dibaca untuk menulisnya.
  • Sama ada syarat yang menjadikan kod sedikit berbeza adalah benar-benar diperlukan.
  • Sama ada jalan pintas menjadikan kod lebih pendek tetapi masih boleh dibaca atau lebih pendek sahaja.

Jika anda mempunyai sebarang maklum balas, mastodon saya, tweet saya, buka isu di GitHub, atau e-mel saya di artem@sapegin.ru. Dapatkan salinan anda.

Atas ialah kandungan terperinci Mencuci kod anda: jangan buat saya berfikir. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan