چگونه کد خود را خواناتر کنیم؟
ﺯﻣﺎﻥ ﻣﻄﺎﻟﻌﻪ: 6 دقیقه

چگونه کد خود را خواناتر کنیم؟

همه ما در مواقعی پیش آمده است که کد بدی نوشته‌ایم. برا جلوگیری از بروز مجدد این اتفاق، همگی به دنبال بهتر کردن مهارت‌های کدنویسی خود هستیم؛ که یعنی نه فقط یاد گفتن فریم‌وورک‌های جدید، بلکه بی نقص کردن آنچه که در حال حاضر بلدیم.

چرا نه تنها یک کد کارآمد، بلکه باید کد خوبی بنویسیم؟

ظاهر کد شما هم به اندازه کارایی محصول یا وبسایت شما مهم است. علت آن این است که ماشین، تنها موجودی نیست که کد شما را می‌خواند.

در درجه نخست، شما بالاخره قرار است که بخشی از کد خود را مجددا بخوانید و وقتی که آن زمان فرا برسد، نوشتن کد کارآمد به شما در درک یا در برطرف کردن آنچه که نوشته‌اید، کمک نمی‌کند.

دوما، اگر در یک تیم کار می‌کنید یا با دیگر توسعه دهندگان همکاری می‌کنید، آن‌ها هم در مواقعی سعی خواهند کرد که کد شما را بخوانند و آنچه که درک می‌کنند را تفسیر کنند. برای آسان‌تر کردن این فعالیت برای آن‌ها، نحوه نامگذاری متغیرها و تابع‌ها، طول هر خط و ساختار کد شما به همراه موارد دیگر مهم هستند.

در ادامه، دستورالعمل‌هایی برای خواناتر کردن کد خود را خواهید دید.

چگونه می‌توان کد بد را تشخیص داد؟

به نظر من بهترین راه برای تشخیص کد بد، این است که سعی کنید آن را به شکل یک جمله یا عبارت بخوانید.

برای مثال در اینجا مقداری کد بد را مشاهده می‌کنید:

تابعی که در بالا نمایش داده شده است، در هنگامی که یک عنصر یا یک تابع شرطی را به آن منتقل کنید، نزدیک‌ترین node والد که با آن تابع شرطی برابری دارد را بر می‌گرداند.

const traverseUpUntil = (el, f) => {

با توجه به این مسئله که کد باید به مانند یک متن معمولی خوانا باشد، خط اول سه اشکال مهلک دارد.

پارامترهای تابع به مانند کلمات خوانا نیستند

  • با این که el معمولا معنای element (عنصر) را دارد و می‌تواند به این صورت درک شود، اما نام پارامتر f هدف خود را نمایش نمی‌دهد.
  • اگر می‌خواستید از این تابع استفاده کنید، معنای «تا زمانی که el از f بگذرد، ادامه بده» را می‌داد که به صورت «تا زمانی که f گذشته شود، ادامه بده» می‌توانست بهتر درک شود. بهترین راه برای انجام این کار، این است که این تابع el.traverseUpUntil(f) نام داشته باشد، اما این خود یک مشکل متفاوت است.

در خط دوم، (let p = el.parentNode) باز هم یک مشکل نام‌گذاری داریم که این بار برای نام یک متغیر است. اگر یک نفر به کد نگاه کند، احتمالا درک خواهد کرد که p چیست. P به معنای parentNode پارامتر el‌ است. گرچه، وقتی که به p در جایی دیگر نگاه می‌کنیم، دیگر مفهوم آن را درک نمی‌کنیم.

while (p.parentNode && !f(p)) {

در این خط، مشکل اصلی‌ای که به آن بر می‌خوریم این است که !f(p) چه معنایی دارد و چیست؛ زیرا در اینجا f می‌تواند هر معنایی داشته باشد. چیزی که یک شخص در حال خواندن کد درک می‌کند، این است که !f(p) یک عملیات بررسی برای این است که ببینیم آیا node فعلی با شرط ما مطابقت دارد یا نه. اگر مطابقت دارد، حلقه را متوقف می‌کنیم.

p = p.parentNode

این مورد کاملا واضح است.

return p

با توجه به نام بد متغیر، خواننده نمی‌تواند به طور ۱۰۰ درصد مطمئن باشد که چه چیزی برگردانده می‌شود.

کد را بهبود دهید

در ابتدا، نام و ترتیب پارامترها را تغییر می‌دهیم: (el, f) => را به (condition, node) => تبدیل می‌کنیم.

شاید در تعجب باشید که من چرا به جای element از node‌ استفاده کردم. به این دلایل:

  • ما در حال نوشتن کد در مفهوم nodeها هستیم. مانند .parentNode، پس چرا آن را ثابت‌تر نکنیم؟
  • استفاده از node کوتاه‌تر از element است، اما باعث از بین رفتن معنا نمی‌شود. این با تمام اشکال nodeها که ویژگی parentNode را دارند کار می‌کند؛ نه فقط عناصر HTML.

حال نام متغیرها را ویرایش می‌کنیم.

let parent = node

این که معنای متغیر را در نامش جای دهید، بسیار مهم است. برای مثال p به معنای parent است. همچنین شاید متوجه شده باشید که ما با node.parentNode شروع نمی‌کنیم. در عوض، فقط با node شروع می‌کنیم.

این ما را به خطوط بعدیمان هدایت می‌کند.

do {
  parent = parent.parentNode
} while (parent.parentNode && !condition(parent))

من به جای یک حلقه while معمولی، به سراغ یک حلقه do … while رفته‌ام. این یعنی از آنجایی که node والد پس از action شرط را اجرا می‌کند، فقط باید یک بار آن را بگیریم. استفاده از حلقه do … while هم در قوانین خواناتر شدن node جای می‌گیرد.

بیایید سعی کنیم آن را بخوانیم: «والد مساوی است با node والد را در حالیکه یک node والد وجود دارد و تابع شرطی مقدار true را بر نمی‌گرداند، اجرا کن.» ممکن است خواندن این جمله کمی سخت باشد، اما در هنگام نوشتن آسان‌تر می‌شود و به ما در درک معنای کد کمک می‌کند.

return parent

با این که افراد زیادی تصمیم می‌گیرند تا از متغیر عمومی ret (یا returnValue) استفاده کنند، خوب نیست که متغیر برگشتی خود را ret نامگذاری کنید. اگر متغیر برگشتی خود را به درستی نامگذاری کنید، چیزی که برگردانده می‌شود، واضح‌تر خواهد شد. گرچه، گاهی اوقات توابع می‌توانند طولانی و دلهره آور باشند، و باعث شوند که کد شما گیج‌کننده‌تر شود. در این صورت، پیشنهاد می‌کنم که تابع خود را به چندین تابع تقسیم کنید، و اگر بیش از حد پیچیده است، اضافه کردن کامنت می‌تواند کمک کند.

کد را ساده‌سازی کنید

حال که کد خود را خوانا کرده‌اید، وقت آن می‌رسد که هر کد غیر ضروری‌ای را از بین ببرید. همانطور که مطمئنم برخی از شما از قبل متوجه شده‌اید، احتمالا اصلا به متغیر parent نیازی نخواهیم داشت.

const traverseUpUntil = (condition, node) => {
  do {
    node = node.parentNode
  } while (node.parentNode && !condition(node))
 
  return node
}

کاری که من انجام داده‌ام، این است که خط اول را برداشته، و parent را با node جایگزین کرده‌ام. این کار، از قدم‌های غیر ضروری ساخت parent می‌گذرد و مستقیما به حلقه می‌رود.

نام متغیرها چه؟

با این که node بهترین توصیف کننده برای این متغیر نیست، اما محبوب‌ترین است. اما بیایید به محبوبیت اهمیت ندهیم و آن را مجددا نامگذاری کنیم. نظرتان درباره «currentNode» (node فعلی) چیست؟

const traverseUpUntil = (condition, currentNode) => {
  do {
    currentNode = currentNode.parentNode
  } while (currentNode.parentNode && !condition(currentNode))
 
  return currentNode
}

این مورد بهتر است! حال وقتی که آن را می‌خوانیم، می‌دانیم که currentNode همیشه نمایانگر nodeای که در حال حاضر استفاده می‌کنیم است.

منبع

چه امتیازی برای این مقاله میدهید؟

خیلی بد
بد
متوسط
خوب
عالی
4 از 1 رای

/@er79ka

دیدگاه و پرسش

برای ارسال دیدگاه لازم است وارد شده یا ثبت‌نام کنید ورود یا ثبت‌نام

در حال دریافت نظرات از سرور، لطفا منتظر بمانید

در حال دریافت نظرات از سرور، لطفا منتظر بمانید