حمید ملارضا
حمید ملارضا
خواندن ۵ دقیقه·۲ سال پیش

به کامپیوتر بگین چی میخواین نه اینکه چطور انجام بده!

بسم الله الرحمن الرحیم

نمونه کد تفکر فانکشنال
نمونه کد تفکر فانکشنال


در این مطلب با مدل فکری فانکشنال آشنا میشین. این مدل فکری وابستگی به زبان برنامه‌نویسی خاصی نداره اما در اینجا از زبان سی‌شارپ استفاده می‌کنیم.

توی برنامه‌نویسی روش فکر کردن خیلی مهمه. اگر درست فکر کنیم می‌تونیم هم مسائل رو بهتر حل کنیم و هم اینکه کدهای تمیزتر، خواناتر، مطمئن‌تر و قابل‌استفاده‌تر تولید کنیم. اینکار لطف بزرگی به خودمون و دیگران هستش و باعث صرفه‌جویی بسیاری در وقت و هزینه‌ها میشه.

یکی از روش‌های خوب فکر کردن، مدل فانکشنال (Functional) هستش. برخلاف تصور خیلی‌ها فانکشنال صرفا مجموعه‌ای از اصول مثل SOLID نیست. بلکه الگو و مدل متفاوتی از نحوه فکر کردن و حل مسئله هستش.

خیلی‌هامون برنامه‌نویسی رو با الگوریتم شروع کردیم و اونجا بهمون گفتن تک تک کارهایی که باید انجام بشه رو به کامپیوتر بگیم. تمرکز این مدل روی چطوری انجام دادن کارها هستش. مثلا اول اینکار رو بکن، بعد اگر فلان حالت بود اینکار رو بکن، اگر نبود اون کار رو بکن... مجموعه‌ای از ifها و forها و...

اما در مدل تفکری فانکشنال، تمرکز بر اینه که ما چی می‌خوایم؟ نه اینکه چطور انجام بشه. اینکه چطور انجام بشه رو به مجموعه‌ای از توابع پایه واگذار می‌کنیم که تست شده، مطمئن، قابل استفاده و خوانا هستن. حالا برای اینکه چنین توابعی (فانکشن/متد) درست کنیم لازمه از اصول و قواعد فانکشنال استفاده کنیم.

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

یه مثال خیلی ساده

فرض کنید «لیستی از اعداد داریم که باید مرتب بشن.»

چی می‌خوایم؟ می‌خوایم این لیست مرتب بشه

چطور باید انجام بشه؟ برای مرتب سازی الگوریتم‌های مختلفی داریم که بعضا هر الگوریتم ممکنه به روش‌های مختلف پیاده‌سازی بشن.

تمرکز تفکر فانکشنال روی اینه که چی می‌خوایم نه اینکه چطور باید انجام بشه. ما می‌خوایم این لیست مرتب بشه. حالا اینکه پشت پرده قراره چطوری پیاده‌سازی بشه، با چه الگوریتمی، به چه روشی و.. به ما ربطی نداره! یا لااقل در ابتدای کار ربطی نداره! اینجا دیگه خبری از پیاده‌سازی کلی if و for و... نیست.

یه مثال ساده دیگه

فرض کنید «لیستی از دانشجوها داریم که باید دانشجوهایی که بالای ۲۲ سال هستن (بزرگتر مساوی ۲۲) رو پیدا کنیم».

روش اول:

var target = new List<Student>(); foreach (var student in students) { if (student.Age < 22) continue; target.Add(student); }

در این مسئله چی می‌خواستیم؟ اما چی کار کردیم؟! بجای اینکه بگیم ای کامپیوتر! برو و دانشجوهای بالای ۲۲ سال رو پیدا کن برام، گفتیم ببین کامپیوتر عزیز! اول یه لیست خالی از دانشجوها تعریف می‌کنی بگو خب! بعدش با یه حلقه foreach میری تک تک دانشجوها رو نگاه می‌کنی بگو خب! بعد اگر سن دانشجو کوچکتر از ۲۲ بود continue میکنی درغیراینصورت اون دانشجو رو به لیست target اضافه میکنی.

به کامپیوتر نگفتیم چی میخوایم، بهش گفتیم چطور انجام بده.

حالا روش دوم که سی‌شارپ کارها به خوبی باهاش آشنا هستن و فانکشنال هستش نگاه کنید.

روش دوم:

var target = students.Where(student => student.Age >= 22).ToList();

من می‌خوام دانشجوهایی که (where) بزرگتر مساوی ۲۲ هستن رو پیدا کنی و در آخر به لیست تبدیل کنی. من اینو میخوام دیگه چطوریش بهم ربطی نداره! (یا قبلا پیاده‌سازی شده یا بعدا پیاده‌سازی میکنم)

در این مثال، متد Where یه متد پایه، تست‌شده، خوانا و قابل استفاده هستش که میتونه در خیلی جاها استفاده بشه.

تفاوت‌ها:

  • خوانایی: با اینکه این مثال، مثال خیلی ساده‌ای هستش اما در روش اول لازمه ۵ خط بخونیم تا متوجه منطق کار بشیم! درحالیکه به وضوح خوانایی روش دوم بسیار بالاست.
  • اطمینان و نگهداری: در روش اول، هم احتمال خطا در پیاده‌سازی بالاست و هم اینکه نگهداری ازش کار سختیه. اما در روش دوم از یک متد پایه‌ای استفاده شده که تست شده و مطمئن هستش.
  • سرعت کدنویسی: به وضوح سرعت کدنویسی در روش دوم بسیار بیشتر از روش اول هستش.
  • قابلیت استفاده مجدد: خیلی سخته بتونیم مجموعه‌ای از ifها و forها رو در جاهای دیگه استفاده کنیم. اینکار هزینه (زمانی، مالی و...) رو بسیار بالا میبره. اما متدهای پایه رو میشه در جاهای زیادی با انواع و اقسام اهداف به کار برد.
این روش به ما کمک میکنه با تمرکز کردن بر منطق برنامه، توابع/متدهای پایه و خوبی تولید کنیم که خوانایی بسیار بالایی دارن، تست شده و مطمئن هستن، قابلیت استفاده بسیار بیشتری دارن و سرعت کدنویسی ما رو بیشتر میکنن.

یه مثال کاملتر

بیایین مثال قبلی رو کمی تعمیم بدیم. فرض کنید «لیستی از دانشجوها داریم که باید از بین دانشجوهای بالای ۲۲ سال، نفر دوم و سوم اون‌ها رو از نظر معدل پیدا کنیم و اسمشون رو نمایش بدیم.»

اگر بخوایم به روش فانکشنال فکر کنیم، توی این مسئله چی می‌خوایم؟

ای کامپیوتر! میخوام دانشجوهایی که ۲۲ سال یا بزرگتر هستن رو پیدا کنی، بعد براساس معدل (زیاد به کم) مرتب کنی، بعد نفر اول رو بیخیال بشی، نفر دوم و سوم رو بگیری، بعد اسمشون رو برام جدا کنی.

خب بیایین همین چیزی که گفتیم رو بنویسیم. خوشبختانه اینجا زبان قدرتمند و مدرن سی‌شارپ رو هم داریم و می‌تونیم از متدهای خوبش استفاده کنیم.

var result = students .Where(student => student.Age > 22) .OrderByDescending(student => student.Average) .Skip(1) .Take(2) .Select(student => student.Name);

هورا! به همین سادگی. :)

کدهای سی‌شارپ

اگر بخواین می‌تونید سورس کامل این مثال رو توی این لینک ببینید. توی متدی به نام Solution1 سعی کردم این مسئله رو به روش قدیمی حل کنم و در Solution2 به روش تفکر فانکشنال.

خروجی نمونه
خروجی نمونه



در آخر

امیدوارم براتون مفید بوده باشه. :)

  • اگر دوست داشتین لایک کنید
  • لینک مطلب رو برای کسایی که فکر می‌کنید به دردشون میخوره بفرستین
  • اگر سوالی هم داشتین همینجا بپرسید یا ایمیل بزنید

ان‌شاءالله در پناه خدا همیشه صبور و شاد و موفق باشین.

فانکشنالکد تمیزسی شارپ
یادداشت‌های شخصی درباره مهندسی نرم‌افزار، کسب و کار، فرهنگی و... به هدف رشد فردی و ان‌شاءالله مفید بودن. 🇵🇸️
شاید از این پست‌ها خوشتان بیاید