برنامهنویسی اعلانی یک پارادایم برنامهنویسی است که در آن منطق و هدف محاسبات بدون شرح چگونگی انجام آنها بیان میشود. Wikipedia فارسی
بعنوان یک برنامهنویس احتمالا چشمتون به این ترکیب خورده، اول از همه چیز باید بگم که به احتمال زیاد هماکنون باهاش آشنا هستید و دلیل اصلیای که دارید این متن رو میخونید، برای مشخص شدن تعریف بهتر اون و از بین بردن تصورات غلط هستش.
تمیز دادن خیلی از مفاهیم کدنویسی بهتون کمک میکنه برنامهنویس بهتری بشید.
در دنیای برنامهنویسی، هر چه بیشتر کد نوشته باشید، احتمال داره بعد از یه زمانی، به جهت عدم تکرار یک سری کدهای تکراری و همچنین تمیزتر پیادهسازی بخشهای برنامه، شروع به نوشتن الگویهای شخصی خودتون کنید، بعدها متوجه میشید این الگو (البته همراه با تغییرات اساسیتر)، با نامی ثبت شده و جزوه مثلا Design pattern قرار گرفته. خوب ما حتما باید با اینها آشنا باشیم، هم با الگو مورد نظر و هم با اسمش! حتی اسمش مهمتر از خودشه?. حتما میپرسید چرا: دلیلش اینکه در کتابها، بلاگها و سخنرانیها وقتی اسمش رو شنیدید رشته ذهنتون از هم پاره نمیشه و مطلب مورد نظر رو بهتر میفهمید.
گرچه کد Declarative جزوه الگوهای طراحی(design patterns) نیست و بیشتر نوعی از استایل و نگاه در کدنویسی محسوب میشه.
برای فهمیدن Declarative ابتدا باید مفهوم Imperative رو بررسی کنیم.
از اونجایی که کامپیوترها ذاتا فهم ندارند!(?، اما خود حقیقته دیگه) شما برای پیاده سازی هدفتون باید لقمه لقمه بهش فهم رو یاد بدید، منظورم اینکه باید بهش دستور بدید، باید ریز به ریز براش شرح بدید! و نهایتا یک برنامه کامپیوتری مجموع این دستورات رو شامل میشه. شاید براتون سوال پیش بیاد که چرا این پاراگراف اینقدر داره ساده به پیش میره، دلیلش اینکه من میخوام به این برسم که مفهموم Declarative صرفا همچنان یک استایل از کدنویسی هستش، برای کامپیتور همهچیز Imperative توصیف میشه.
من عمیقا فکر میکنم باید به مفاهیم برنامهنویسی با دید فلسفی(چرایی) نگاه کرد. با پرسیدن و چرایی، ذهن شروع به مقایسه کردن و نتیجتا یادگیری میکنه! این باید تبدیل به یک عادت بشه.
خوب مقدمه کافیه! فکر میکنم بایدحالا با این استایل بیشتر آشنا بشیم و بعد وارد فلسفش بشیم.
پارادایم دستوری (Imperative paradigm): به چطور انجام شدن کارها اشاره میکنه.
پارادایم اعلانی (Declarative paradigm): به اینکه چه کاری باید انجام بشه اشاره میکنه.
یه مثال، فکر کنید رئیس شرکتی هستید و هوس نوشیدن چای کردید، این رو اگه بخوایم به این دو حالت بیان کنیم یه چیزی شبیه این میشه:
imperative: به خدمتکارتون میگید که بره ببینه چای خشک داریم یا نه، اگه داریم زیر ساموَر رو روشن کن و وقتی آب جوش اومد چای بریز در قوری... بعد استکان رو از هر کشویی که دراون استکان هست، بگیرو چای بریز.(همینجوری حالا یه مثالی زدم، مناقشه در این مثال جایز نیست?)
خوب declarative: یک چای برام آماده کن.
همونطور که گفته شد، روش اول چطور انجام شدن کار و روش دوم اینکه چه کاری باید انجام بشه رو توضیح میده.
خوب بریم سراغ مثال مشخص تر در کد:
let found = null; let numbers = [5, 12, 8, 130, 44]; for ( let i = 0; i < numbers.length; i++ ) { if( numbers[i] > 10 ){ found = numbers[i]; break; } }
این کد جاوااسکریپت توی یه آرایه میگرده و اولین آیتمی که بالاتر از 10 باشه رو در found ذخیره میکنه و از حلقه میاد بیرون، حالا این مثال رو به شکل Declarative مینویسیم.
let numbers = [5, 12, 8, 130, 44]; numbers.find(item => item > 10)
کد توضیح نمیده که چطور آیتم پیدا شده، صرفا میگه چی میخواد.(اولین آیتم بالای 10)
خوب شاید فکر کنید که جادوی خاصی اتفاق نیوفتاده و ما صرفا قسمت دستوری یا Imperative کد رو جدا کردیم و منتقل کردیم درون یک فانکشن با اسمِ مناسب. بله دقیقا همینطوره که گفتم، کد Declarative صرفا یک استایل کدنویسی هستش که شما با ایجاد لایه و پنهانکردن بخش های Imperative کد، ساختار کد رو به سمتی میبرید که ذهن انسان راحتتر درکش کنه.
همه فکر میکنند که کد برای کامپیوترها نوشته میشه، اما در حقیقت برای انسانها نوشته میشه.
واقعا اینه! اینهمه داستان، از برنامهنویسی فانکشنال گرفته تا شیگرایی همه و همه برای اینکه برنامهنویس بهتر کد بنویسه و همتیمیهای فعلی یا آیندش بهتر و سریعتر بتونن از اون کد سر در بیارن. به عبارتی همون خوانایی.
کدی خواناست که تا میتونه بهتر با برنامهنویس ارتباط بگیره. Declarative بودن کد تماما برای این هدفه.
صحبت از همتیمی شد، یکی از همتیمیهایی که شما در آینده باهاش ملاقات میکنید خودتون هستید، منظورم اینکه شما خیلی مواقع برمیگردید به کدهای یک سال پیشتون و قالبا هیچ چیزی ازش به خاطرتون نمیاد.
ریاکت و تمامی کتابخانههای اینچنینی و آنچنینی بعنوان مثال، تماما برای این ساخته شده که برنامهنویس(شرکت یا تیم توسعه) بتونه قابلیتهای بیشتر یا همون کدهای بیشتری به پروژه اضافه بکنه، بدون اینکه رشته کار از دستش پاره بشه (این جای بحث داره البته)، گرچه لازم میدونم اینو بگم ریاکت و یا هر کتابخونهی دیگه این رو ضمانت نمیکنه، این صرفا یک ابزاره، و ما باید همیشه حواسمون باشه که در حد یک ابزار ببینیمش نه کلید حل تمامیه مشکلات.
صحبت از ریاکت شد، اتفاقا در تعاریفش از Declarative بودن بعنوان خوبیهاش گفته:
پاراگراف آخر بعنوان نتیجهگیری، از قابل پیشبینی بودن و راحتتر خطایابی کردن کد Declarative صحبت میکنه. (البته در بخش view)
خوب برگردیم سراغ همون مثال بالا. سوال اساسی که باید الان مطرح بشه اینه: تا کجا؟
تا کجا یا بهتره بگم تا چه میزان کدهامون رو لایهبندی یا به اصطلاح ماژولار کنیم؟ این سوالیه که جواب دقیق "یک خطی" نداره و باید بهش مفصل پرداخت اما میشه گفت بستگی به تجربه و اینکه چقدر علاقمند هستید که کدتون خوب باشه برمیگرده.
اینکه کدی رو بنویسید که به اصطلاح "فقط کار کنه" یعنی به پیادهسازی بهتر کد فکر نمیکنید.
آیا معایبی هم در استایل کدنویسی Declarative وجود داره؟ تا چطور عیب رو تعریف کنیم، وقتی قسمت imperative کد از دید شما پنهان شده، چقدر مطمئن هستید که چطور پیادهسازی شده؟ خوب مساله اینجاست، توی مثال find در بالا، ما خیالمون جمعه که فانکشن Array.prototype.find تبدیل شده به استندارد زبان(در اینجا جاوااسرکیپت)، اما فرض کنید که همچین فانکشنی رو همکارتون نوشته باشه و باگی داشته باشه. حالا آیا این واقعا عیب Declarative بودنه؟ واقعا نه. من تلاش میکنم که بگم چون قسمتی از کد در جای دیگه هست امکان داره شما از نوع پیادهسازیش مطمئن نباشید. شاید همین باعث بشه شما از قابلیت بیشتر اون هم غافل بمونید. که البته همه اینها دارای راه چاره میباشند.?
ممنون که با من همراه بودید، خوب این متن در حال تکمیل شدنه و من صرفا خواستم شروعش کرده باشم و بعد با مثالها و توضیحات بیشتر به این متن شاخ و برگ بیشتری بدم، نظراتتون بسیار توی این راه کمکم میکنه.