Tingkatkan Pengetahuan JavaScript Anda Dengan Membaca Kode Sumber

Diterbitkan: 2022-03-10
Ringkasan cepat Ketika Anda masih berada di awal karir pemrograman Anda, menggali kode sumber perpustakaan dan kerangka kerja sumber terbuka bisa menjadi usaha yang menakutkan. Dalam artikel ini, Carl Mungazi membagikan bagaimana dia mengatasi rasa takutnya dan mulai menggunakan kode sumber untuk meningkatkan pengetahuan dan keterampilannya. Dia juga menggunakan Redux untuk mendemonstrasikan bagaimana dia mendekati penghancuran perpustakaan.

Apakah Anda ingat pertama kali Anda menggali jauh ke dalam kode sumber perpustakaan atau kerangka kerja yang sering Anda gunakan? Bagi saya, momen itu datang selama pekerjaan pertama saya sebagai pengembang frontend tiga tahun lalu.

Kami baru saja selesai menulis ulang kerangka warisan internal yang kami gunakan untuk membuat kursus e-learning. Pada awal penulisan ulang, kami telah menghabiskan waktu menyelidiki sejumlah solusi berbeda termasuk Mithril, Inferno, Angular, React, Aurelia, Vue, dan Polymer. Karena saya masih sangat pemula (saya baru saja beralih dari jurnalisme ke pengembangan web), saya ingat merasa terintimidasi oleh kerumitan setiap kerangka kerja dan tidak memahami cara kerja masing-masing kerangka kerja.

Pemahaman saya tumbuh ketika saya mulai menyelidiki kerangka kerja pilihan kami, Mithril, secara lebih mendalam. Sejak itu, pengetahuan saya tentang JavaScript — dan pemrograman secara umum — sangat terbantu dengan berjam-jam yang saya habiskan untuk menggali jauh ke dalam perpustakaan yang saya gunakan setiap hari baik di tempat kerja atau di proyek saya sendiri. Dalam posting ini, saya akan membagikan beberapa cara Anda dapat mengambil perpustakaan atau kerangka kerja favorit Anda dan menggunakannya sebagai alat pendidikan.

Kode sumber untuk fungsi hyperscript Mithril
Pengenalan pertama saya untuk membaca kode adalah melalui fungsi hyperscript Mithril. (Pratinjau besar)
Lebih banyak setelah melompat! Lanjutkan membaca di bawah ini

Manfaat Membaca Kode Sumber

Salah satu manfaat utama membaca kode sumber adalah banyaknya hal yang dapat Anda pelajari. Ketika saya pertama kali melihat ke basis kode Mithril, saya memiliki gagasan yang kabur tentang apa itu DOM virtual. Ketika saya selesai, saya datang dengan pengetahuan bahwa DOM virtual adalah teknik yang melibatkan pembuatan pohon objek yang menggambarkan seperti apa tampilan antarmuka pengguna Anda. Pohon itu kemudian diubah menjadi elemen DOM menggunakan API DOM seperti document.createElement . Pembaruan dilakukan dengan membuat pohon baru yang menjelaskan status antarmuka pengguna di masa mendatang dan kemudian membandingkannya dengan objek dari pohon lama.

Saya telah membaca tentang semua ini di berbagai artikel dan tutorial, dan meskipun itu membantu, dapat mengamatinya di tempat kerja dalam konteks aplikasi yang telah kami kirimkan sangat mencerahkan bagi saya. Itu juga mengajari saya pertanyaan mana yang harus diajukan ketika membandingkan kerangka kerja yang berbeda. Alih-alih melihat bintang GitHub, misalnya, sekarang saya tahu untuk mengajukan pertanyaan seperti, "Bagaimana cara setiap kerangka kerja melakukan pembaruan memengaruhi kinerja dan pengalaman pengguna?"

Manfaat lainnya adalah peningkatan apresiasi dan pemahaman Anda terhadap arsitektur aplikasi yang baik. Sementara sebagian besar proyek open-source umumnya mengikuti struktur yang sama dengan repositori mereka, masing-masing mengandung perbedaan. Struktur Mithril cukup datar dan jika Anda terbiasa dengan API-nya, Anda dapat membuat tebakan terpelajar tentang kode di folder seperti render , router dan request . Di sisi lain, struktur React mencerminkan arsitektur barunya. Pengelola telah memisahkan modul yang bertanggung jawab untuk pembaruan UI ( react-reconciler ) dari modul yang bertanggung jawab untuk merender elemen DOM ( react-dom ).

Salah satu keuntungannya adalah sekarang lebih mudah bagi pengembang untuk menulis perender kustom mereka sendiri dengan menghubungkan ke paket react-reconciler . Parcel, bundler modul yang saya pelajari baru-baru ini, juga memiliki folder packages seperti React. Modul kunci bernama parcel-bundler dan berisi kode yang bertanggung jawab untuk membuat bundel, memutar server modul panas dan alat baris perintah.

Bagian dari spesifikasi JavaScript yang menjelaskan cara kerja Object.prototype.toString
Tidak akan lama sebelum kode sumber yang Anda baca membawa Anda ke spesifikasi JavaScript. (Pratinjau besar)

Namun manfaat lain — yang mengejutkan saya — adalah Anda menjadi lebih nyaman membaca spesifikasi JavaScript resmi yang mendefinisikan cara kerja bahasa. Pertama kali saya membaca spesifikasinya adalah ketika saya sedang menyelidiki perbedaan antara throw Error dan throw new Error (spoiler alert — tidak ada). Saya memeriksa ini karena saya perhatikan bahwa Mithril menggunakan throw Error dalam implementasi fungsi m -nya dan saya bertanya-tanya apakah ada manfaat menggunakannya daripada throw new Error . Sejak itu, saya juga belajar bahwa operator logika && dan || tidak selalu mengembalikan boolean, menemukan aturan yang mengatur bagaimana operator kesetaraan == memaksa nilai dan alasan Object.prototype.toString.call({}) mengembalikan '[object Object]' .

Teknik Untuk Membaca Kode Sumber

Ada banyak cara untuk mendekati kode sumber. Saya telah menemukan cara termudah untuk memulai adalah dengan memilih metode dari perpustakaan pilihan Anda dan mendokumentasikan apa yang terjadi ketika Anda memanggilnya. Jangan mendokumentasikan setiap langkah, tetapi cobalah untuk mengidentifikasi aliran dan strukturnya secara keseluruhan.

Saya melakukan ini baru-baru ini dengan ReactDOM.render dan akibatnya belajar banyak tentang React Fiber dan beberapa alasan di balik implementasinya. Untungnya, karena React adalah framework yang populer, saya menemukan banyak artikel yang ditulis oleh pengembang lain tentang masalah yang sama dan ini mempercepat prosesnya.

Penyelaman mendalam ini juga memperkenalkan saya pada konsep penjadwalan kooperatif, metode window.requestIdleCallback dan contoh dunia nyata dari daftar tertaut (React menangani pembaruan dengan menempatkannya dalam antrian yang merupakan daftar tertaut dari pembaruan yang diprioritaskan). Saat melakukan ini, disarankan untuk membuat aplikasi yang sangat mendasar menggunakan perpustakaan. Ini memudahkan saat debugging karena Anda tidak harus berurusan dengan jejak tumpukan yang disebabkan oleh perpustakaan lain.

Jika saya tidak melakukan tinjauan mendalam, saya akan membuka folder /node_modules di proyek yang sedang saya kerjakan atau saya akan pergi ke repositori GitHub. Ini biasanya terjadi ketika saya menemukan bug atau fitur menarik. Saat membaca kode di GitHub, pastikan Anda membaca dari versi terbaru. Anda dapat melihat kode dari komit dengan tag versi terbaru dengan mengklik tombol yang digunakan untuk mengubah cabang dan memilih "tag". Pustaka dan kerangka kerja selalu mengalami perubahan sehingga Anda tidak ingin mempelajari sesuatu yang mungkin akan dihapus di versi berikutnya.

Cara lain yang kurang terlibat dalam membaca kode sumber adalah apa yang saya sebut metode 'sekilas sekilas'. Sejak awal ketika saya mulai membaca kode, saya menginstal express.js , membuka folder /node_modules dan memeriksa dependensinya. Jika README tidak memberi saya penjelasan yang memuaskan, saya membaca sumbernya. Melakukan ini membawa saya ke temuan menarik ini:

  • Express bergantung pada dua modul yang keduanya menggabungkan objek tetapi melakukannya dengan cara yang sangat berbeda. merge-descriptors hanya menambahkan properti yang langsung ditemukan langsung pada objek sumber dan juga menggabungkan properti non-enumerable sementara utils-merge hanya mengulangi properti enumerable objek serta yang ditemukan dalam rantai prototipe. merge-descriptors menggunakan Object.getOwnPropertyNames() dan Object.getOwnPropertyDescriptor() sementara utils-merge menggunakan for..in ;
  • Modul setprototypeof menyediakan cara lintas platform untuk mengatur prototipe objek yang dipakai;
  • escape-html adalah modul 78-baris untuk keluar dari string konten sehingga dapat diinterpolasi dalam konten HTML.

Meskipun temuannya kemungkinan besar tidak akan berguna dengan segera, memiliki pemahaman umum tentang dependensi yang digunakan oleh pustaka atau kerangka kerja Anda akan berguna.

Ketika datang untuk men-debug kode front-end, alat debugging browser Anda adalah teman terbaik Anda. Antara lain, mereka memungkinkan Anda untuk menghentikan program kapan saja dan memeriksa statusnya, melewati eksekusi fungsi atau masuk atau keluar darinya. Terkadang hal ini tidak dapat segera dilakukan karena kode telah diperkecil. Saya cenderung menghapusnya dan menyalin kode yang tidak diperkecil ke dalam file yang relevan di folder /node_modules .

Kode sumber untuk fungsi ReactDOM.render
Pendekatan debugging seperti yang Anda lakukan pada aplikasi lain. Buatlah hipotesis dan kemudian ujilah. (Pratinjau besar)

Studi Kasus: Fungsi Connect Redux

React-Redux adalah library yang digunakan untuk mengelola status aplikasi React. Ketika berhadapan dengan perpustakaan populer seperti ini, saya mulai dengan mencari artikel yang telah ditulis tentang implementasinya. Dalam melakukannya untuk studi kasus ini, saya menemukan artikel ini. Ini adalah hal baik lainnya tentang membaca kode sumber. Fase penelitian biasanya membawa Anda ke artikel informatif seperti ini yang hanya meningkatkan pemikiran dan pemahaman Anda sendiri.

connect adalah fungsi React-Redux yang menghubungkan komponen React ke toko Redux aplikasi. Bagaimana? Nah, menurut dokumen, ia melakukan hal berikut:

"...mengembalikan kelas komponen baru yang terhubung yang membungkus komponen yang Anda masukkan."

Setelah membaca ini, saya akan mengajukan pertanyaan berikut:

  • Apakah saya tahu pola atau konsep di mana fungsi mengambil input dan kemudian mengembalikan input yang sama yang dibungkus dengan fungsionalitas tambahan?
  • Jika saya mengetahui pola seperti itu, bagaimana saya menerapkannya berdasarkan penjelasan yang diberikan dalam dokumen?

Biasanya, langkah selanjutnya adalah membuat aplikasi contoh yang sangat mendasar yang menggunakan connect . Namun, pada kesempatan ini saya memilih untuk menggunakan aplikasi React baru yang kami buat di Limejump karena saya ingin memahami connect dalam konteks aplikasi yang pada akhirnya akan masuk ke lingkungan produksi.

Komponen yang saya fokuskan terlihat seperti ini:

 class MarketContainer extends Component { // code omitted for brevity } const mapDispatchToProps = dispatch => { return { updateSummary: (summary, start, today) => dispatch(updateSummary(summary, start, today)) } } export default connect(null, mapDispatchToProps)(MarketContainer);

Ini adalah komponen wadah yang membungkus empat komponen terhubung yang lebih kecil. Salah satu hal pertama yang Anda temukan dalam file yang mengekspor metode connect adalah komentar ini: connect adalah fasad di atas connectAdvanced . Tanpa melangkah jauh, kami memiliki momen pembelajaran pertama kami: kesempatan untuk mengamati pola desain fasad beraksi . Di akhir file kita melihat bahwa connect mengekspor sebuah pemanggilan fungsi yang disebut createConnect . Parameternya adalah sekumpulan nilai default yang telah dirusak seperti ini:

 export function createConnect({ connectHOC = connectAdvanced, mapStateToPropsFactories = defaultMapStateToPropsFactories, mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories, mergePropsFactories = defaultMergePropsFactories, selectorFactory = defaultSelectorFactory } = {})

Sekali lagi, kami menemukan momen pembelajaran lain: mengekspor fungsi yang dipanggil dan merusak argumen fungsi default . Bagian destructuring adalah momen pembelajaran karena seandainya kodenya ditulis seperti ini:

 export function createConnect({ connectHOC = connectAdvanced, mapStateToPropsFactories = defaultMapStateToPropsFactories, mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories, mergePropsFactories = defaultMergePropsFactories, selectorFactory = defaultSelectorFactory })

Itu akan menghasilkan kesalahan ini Uncaught TypeError: Cannot destructure property 'connectHOC' of 'undefined' or 'null'. Ini karena fungsi tidak memiliki argumen default untuk digunakan kembali.

Catatan : Untuk lebih lanjut tentang ini, Anda dapat membaca artikel David Walsh. Beberapa momen belajar mungkin tampak sepele, tergantung pada pengetahuan Anda tentang bahasa tersebut, jadi mungkin lebih baik untuk fokus pada hal-hal yang belum pernah Anda lihat sebelumnya atau perlu dipelajari lebih lanjut.

createConnect sendiri tidak melakukan apa pun di badan fungsinya. Ini mengembalikan fungsi yang disebut connect , yang saya gunakan di sini:

 export default connect(null, mapDispatchToProps)(MarketContainer)

Dibutuhkan empat argumen, semuanya opsional, dan tiga argumen pertama masing-masing melalui fungsi match yang membantu menentukan perilakunya menurut apakah argumen itu ada dan tipe nilainya. Sekarang, karena argumen kedua yang disediakan untuk match adalah salah satu dari tiga fungsi yang diimpor ke connect , saya harus memutuskan utas mana yang akan diikuti.

Ada saat-saat pembelajaran dengan fungsi proxy yang digunakan untuk membungkus argumen pertama untuk connect jika argumen tersebut adalah fungsi, utilitas isPlainObject yang digunakan untuk memeriksa objek biasa atau modul warning yang mengungkapkan bagaimana Anda dapat mengatur debugger Anda untuk memecahkan semua pengecualian. Setelah fungsi match, kita masuk ke connectHOC , fungsi yang mengambil komponen React kita dan menghubungkannya ke Redux. Ini adalah pemanggilan fungsi lain yang mengembalikan wrapWithConnect , fungsi yang sebenarnya menangani menghubungkan komponen ke toko.

Melihat implementasi connectHOC , saya dapat menghargai mengapa perlu connect untuk menyembunyikan detail implementasinya. Ini adalah inti dari React-Redux dan berisi logika yang tidak perlu diekspos melalui connect . Meskipun saya akan mengakhiri penyelaman mendalam di sini, jika saya melanjutkan, ini akan menjadi waktu yang tepat untuk berkonsultasi dengan bahan referensi yang saya temukan sebelumnya karena berisi penjelasan yang sangat rinci tentang basis kode.

Ringkasan

Membaca kode sumber sulit pada awalnya tetapi seperti apa pun, itu menjadi lebih mudah seiring waktu. Tujuannya bukan untuk memahami segalanya tetapi untuk mendapatkan perspektif dan pengetahuan baru yang berbeda. Kuncinya adalah berhati-hati tentang seluruh proses dan sangat ingin tahu tentang segalanya.

Sebagai contoh, saya menemukan fungsi isPlainObject menarik karena menggunakan this if (typeof obj !== 'object' || obj === null) return false untuk memastikan argumen yang diberikan adalah objek biasa. Ketika saya pertama kali membaca implementasinya, saya bertanya-tanya mengapa tidak menggunakan Object.prototype.toString.call(opts) !== '[object Object]' , yang lebih sedikit kode dan membedakan antara objek dan sub tipe objek seperti Tanggal obyek. Namun, membaca baris berikutnya mengungkapkan bahwa dalam kejadian yang sangat tidak mungkin bahwa pengembang yang menggunakan connect mengembalikan objek Date, misalnya, ini akan ditangani oleh Object.getPrototypeOf(obj) === null .

Sedikit intrik lain di isPlainObject adalah kode ini:

 while (Object.getPrototypeOf(baseProto) !== null) { baseProto = Object.getPrototypeOf(baseProto) }

Beberapa pencarian Google membawa saya ke utas StackOverflow ini dan masalah Redux yang menjelaskan bagaimana kode itu menangani kasus-kasus seperti memeriksa objek yang berasal dari iFrame.

Tautan Berguna Saat Membaca Kode Sumber

  • “Cara Membalikkan Kerangka Insinyur,” Max Koretskyi, Medium
  • “Cara Membaca Kode,” Aria Stewart, GitHub