مینیمالیسم : در راستای حل مسئله در برنامه نویسی
تو این پست قراره نگاهی به منابع و رویکرد های حل مسئله در برنامه نویسی داشته باشیم.
بازگشت به ریپوهای قدیمی
شروع مسیر من تو برنامه نویسی با ناامیدی زیادی همراه بود. اوایل که شروع میکنی ممکنه حس درجا زدن داشته باشی، حس کنی که هیچ پیشرفتی وجود نداره اما وقتی که به خودت زمان بدی و راه درست رو پیدا کنی این احساسات محو میشن.
1.ما انسان های عجولی هستیم .
نمیدونم دقیقا بشر از چه زمانی شروع کرد به سریع تر و سریع تر، خواستن و رسیدن. شاید از وقتی که متوجه شد چقدر این دنیا بزرگه و چقدر چیزهای زیادی وجود داره که هیچوقت نمیتونه همه شون رو داشته باشه. این تشنگی و عطش برای خواستن داره نابود مون میکنه. من تو این مسیر بود که یادگرفتم هرچیز خوبی زمان میبره و باید مدت خوبی براش تمرکز کنی ، بهش انرژی و توجه بدی و امیدوار باشی که به نتیجه برسی. عجله دشمن یادگیری هست، تمرکز رو از بین میبره و ما رو از مسیر اصلی مون دور میکنه . عادت کردن به اینکه تو هر مسیری زود نتیجه بگیریم، فکر نکنم اصلا تو برنامه نویسی جواب بده! به جاش باید از مسیر لذت برد و تو checkpoint های معینی، نتایج رو بررسی کرد.
2. مشورت کن! ولی بعد اینکه تمام تلاشتو کردی.
تصمیم گرفتم این پست رو بنویسم چون به شکل های مختلف تفاوت نگاه آدمی که حل مسئله بلده و آدمی که بلد نیست رو دیدم. بعد از چند ماه به ریپوی قدیمی ام برگشتم و این بار سعی کردم دوباره یادبگیرم. به طرز عجیبی دیگه مثل قبل ناامید نشدم، گیج نشدم و نحوه رسیدن به layout مناسب خیلی کمتر زمان برد، ذهن من یادگرفت سلسله مراتبی به مشکلی که روبروش هست نگاه کنه.
یادمه قبلا چقدر با ساده ترین سوالات مشکل داشتم، دائم میخواستم حل بشه هرطوری که هست، از بقیه بپرسم ، سرچ کنم یا حتی یه مدت بیخیالش بشم. ولی الان بعد چندماه که یادگیری # C رو شروع کردم، دیگه دنبال جواب سریع و آماده نیستم، هر چیزی رو سرچ میکنم حتی بیخود ترین سوالات ممکن رو و به عنوان آخرین و تنها ترین راه حل اگه نتونم هیچ جوابی پیدا کنم سراغ Stack Overflow میرم.
پنج تا از بهترین دوستان شما اینهاست : بپرسید چه چیز، چرا، چه جا، چه وقت و چگونه و هنگامی که نیاز به اندرز دارید از هیچکس دیگر چیزی نپرسید.
3. ساده فکر کنید : هر چی کمتر بهتر
میخوام باهاتون یکی از مهم ترین اکتشافات اخیرم رو در میون بذارم :) اینکه خیلی از اطرافیانم و خودم، به جای اینکه به ساده ترین راه حل ممکنی که الان برای مشکل وجود داره فکر کنیم، دنبال سخت ترین، دور از دسترس ترین و غیر ممکن ترین راه حل میگردیم و امید داریم اینطوری به نتیجه هم برسیم. واقعا چرا اولین راه حل ساده ای که روبرو مون هست رو نمیبینیم و دنبال پیچیده کردن همه چی هستیم ؟ مشکل مینیمالیست بودن چیه؟ :D تو این مدت که چالش صد روز کد رو شروع کردم، متوجه این موضوع شدم، که همیشه دارم برای حل کردن سوالم دنبال راه سختش میرم وقتی تمرکز کردم روی این چالش، خیلی از جزئیات ریز و مهمی که ازش بی خبر بودم پیداشون شد، صحبت کردن با آدم های حرفه ای باعث شد حتی بیشتر توجه ام به این نکته جلب بشه . چند وقت پیش یه متنی رو خوندم و اینجا هم خلاصه اش رو گذاشتم، با آقای آخی در این مورد صحبت میکردیم که این نوع از خطاهای کامپیوتری که موقع گرد کردن و کار با اعداد تو محدوده خاصی اتفاق میافته محدود به کامپیوتر ها نمیشه و از زمانی که اینترنت رشد پیدا کرد به شیوه های جدیدی برای ذخیره سازی اعداد نیاز داشتیم، اما بدلیل استفاده از ابزارهای سطح بالا و نزدیک به زبان انسان این موضوع رو متوجه نمیشیم و حتی شارژر های موبایل هم از این قائده مستثنی نیستن :
خیلی پیش پا افتادهتر فکر کن .همین اپل و اندروید اتحادیه اروپا اپل رو مجبور کرد که اون هم بیاد از تایپسی استفاده کنه که توی اندروید وجود داره. اپل اومده یه شارژر تایپ سی طراحی کرده که به تمام گوشیهای تایپ سی دنیا میخوره اما هیچ شارژر تایپ سی دیگهای روی اپل کار نمیکنه??♂️?
حل مسئله
Divide and Conquer: make it to small pieces.
یه ویدئو از یوتیوب چند وقت پیش میدیدم، درمورد این که چطور سوالات Leetcode رو حل کنیم، نکته ای گفت که خیلی مهم بود : همه تازه کار ها وقتی با یه سوال جدید روبرو میشن، سریع دست به کار میشن و شروع به نوشتن کد میکنن، امتحان میکنن و سعی میکنن از طریق تغیر دادن و تست کردن به جواب برسن. من همیشه همین کار رو انجام میدادم و خیلی وقت ها طول میکشید که به جواب برسم ولی حرفه ای ها، چند دقیقه اول رو فقط صرف فکر کردن به سوال میکنن، درک سوال و فهمیدن اینکه چه چیزی ازمون میخواد نصف بیشتر مسیر هست . تازه مرحله دوم هم کد زدن نیست. حل کردن سوال بدون نوشتن کد هست، وقتی سوال رو متوجه شدی پس الان حتما یه راه حل براش تو ذهنت داری، و باید بتونی این مراحل رو برای خودت واضح کنی تا جایی که به حل سوال برسی.
مرحله آخر میشه عملی کردن راه حلی که تو ذهن مون داریم به شکل کد. به عبارت دیگه یه کار رو اون قدر به مراحل کوچیک تقسیم کن که راحت بتونی انجامش بدی. کاری که من انجام میدادم این بود که سعی داشتم یه مسئله سخت رو بدون داشتن قدم های کوچیک حل کنم. این شکستن مسئله به اجزا کوچیک تر و انجام دادن هر بخش کوچیک، مفهوم اصلی یکی از مهم ترین الگوریتم ها یعنی Divide and Conquer هست .
دوست خوبم مهدیس دانشجوی کارشناسی ریاضی شهید بهشتی، کتاب چگونه مسئله را حل کنیم نوشته جورج پولیا رو بهم معرفی کرده بود.
قسمت هایی از کتاب رو در راستای مراحل حل سوال براتون میذارم :
فهمیدن مسئله : اول باید مسئله را بفهمید
مجهول چیست ؟ داده ها کدام است ؟ شرط چیست ؟ شکلی رسم کنید. علامت های مناسب رو به کار ببرید.
طرح نقشه : ارتباط میان داده ها و مجهول را پیدا کنید. ممکنه در صورت پیدا نکردن ارتباط مستقیم بین داده ها و مجهول، مسئله های کمکی در نظر بگیرید. باید سرانجام یک نقشه برای مسئله طرح کنید.
آیا آن را پیشتر دیده بودید ؟ آیا همین مسئله را به صورت دیگر دیده اید ؟ ( وصل کردن اطلاعات گذشته به وضعیت فعلی باعث تحریک نورون ها و یادگیری بهتر میشه ). به مجهول نگاه کنید! و بکوشید تا درباره مسئله ای بیاندیشید که همین مجهول یا شبیه آن را داشته باشد. در این جا مسئله ای وابسته به مسئله شما وجود دارد که پیشتر حل شده است، آیا میتوانید آن را به کار ببرید ؟ آیا میتوانید روش آن را به کار ببرید؟ آیا باید یک عنصر کمکی را وارد کنید تا به کار بردن آن را ممکن سازد ؟ آیا میتوانید صورت مسئله را دوباره بیان کنید ؟ آیا میتوانید آن را به صورتی دیگر بیان کنید ؟ به تعریف ها رجوع کنید. اگر نمیتوانید مسئله طرح شده را حل کنید، نخست به حل کردن مسئله ای وابسته به آن بپردازید. آیا میتوانید مسئله وابسته ای را که بیشتر در دسترس باشد تخیل کنید ؟
سوم : اجرای نقشه
در ضمن اجرای نقشه حل مسئله، هر گام را که برمیدارید وارسی و امتحان کنید . آیا میتوانید آشکارا ببینید که گام برداشته شده درست بوده است ؟ آیا میتوانید درست بودن آن را ثابت کنید ؟
چهارم : امتحان کردن جوابی که به دست آمده، یعنی به عقب نگاه کردن .
آیا میتوانید نتیجه را بررسی کنید ؟ آیا میتوانید نتیجه را از راهی دیگر بدست آورید ؟ آیا میتوانید نتیجه یا روش را در مسئله ای دیگر به کار ببرید ؟
حل کردن مسائل، همچون مثلا شناوری، یک مهارت تمرینی و عملی است. هر مهارت عملی را از راه تقلید و تمرین بدست میآوریم. برای آموختن شنا از کاری که دیگران با دست و پای خود انجام میدهند تا سر خود را بالای آب نگاه دارند، تقلید میکنید و سرانجام با تمرین کافی شایستگی شنا کردن بهره شما میشود. برای آموختن فن حل مسائل باید به ملاحظه و مشاهده آنچه دیگران برای حل مسئله میکنند و تقلید از ایشان بپردازید و سرانجام خود میآموزید که چگونه در ساختن مسائل توفیق حاصل کنید.
گشتن در پیرامون یک مانع، همان کاری است که ما در حل هرگونه مسئله انجام میدهیم.
مثال
با یه سوال ساده از بحثLINQ های #C شروع کنیم .
فرض کنید، اطلاعات دانش آموز ها رو به این شکل داخل فایل StudentDatabase.cs ذخیره کردیم :
public static IQueryable<Student> GetStudentsFromDb()
{
return new[] {
new Student() {StudentId = 1, StudentName = "John Bross", Score = 82, StudentCity = "NYC", StudentActvity = true},
new Student() {StudentId = 2, StudentName = "Jasmine Curly", Score = 84, StudentCity = "NYC", StudentActvity = false},
new Student() {StudentId = 4, StudentName = "Ben Wild", Score = 65, StudentCity = "CA", StudentActvity = true},
new Student() {StudentId = 6, StudentName = "Sara Ride", Score = 81, StudentCity = "CA", StudentActvity = true},
new Student() {StudentId = 7, StudentName = "Bonnie Brooklyn", Score = 80, StudentCity = "LA", StudentActvity = false},
new Student() {StudentId = 8, StudentName = "Loren Gibson", Score = 88, StudentCity = "CA", StudentActvity = false},
}.AsQueryable();
}
حالا میخوایم اسم دانش آموزانی رو داشته باشیم که score بالای 80 دارن. چطور انجامش میدین ؟
var studentsList = GetStudentsList();
studentsScoreMoreThan80 = studentsList.Where(x => x.Score > 80).Select(x => x.StudentName);
foreach (var item in studentsScoreMoreThan80)
{
Console.WriteLine(item);
}
حالا اگه همین سوال رو یه کم سخت تر کنیم، با توجه به مراحلی که گفتیم باید بتونید با توجه به سوال قبلی، مقایسه کردن، سرچ کردن و بررسی کد تون، حلش کنید.
این بار اسم دانش آموزهایی که فعال score بالای 80 و شهر نیویورک هستن رو پیدا کنید.
با توجه به سوال قبلی، باید مطمئن بشیم که Lambda Expressions و مباحث دیگه رو بلد هستیم، پس اگه یادتون رفته مثلا این عبارت #Lambda Expressions in C رو سرچ کنید تا چند نمونه و توضیح ببینید.
//Access to the class metho
var studentList = StudentDatabase.GetStudentsFromDb();
var studentsName1 = studentList.Where(x => x.StudentActvity && x.Score > 80 && x.StudentCity == "NYC").Select(x => x.StudentName);
foreach (var item1 in studentsName1)
{
Console.WriteLine($"Students with true activity, score > 80 and NY city : {item1}");
}
میتونید این کد رو بهتر کنید ؟ اگه راه حل کوتاه تر و بهتری دارین پس سعی کنید اونا رو هم امتحان کنید مثلا من پرانتز های اضافی و && های اضافی رو حذف کردم. و همچنین میتونید ریپوزیتوری این برنامه رو از اینجا ببینید.
پایان
همونطور که جورج پولیا گفته :
حل کردن مسائل یکی از فعالیت های بنیادی انسان است. بعضی از اشخاص در رسیدن به هدف های خود که حل کردن مسائل است کامیابی بیشتری دارند و بعضی کمتر. باید میل به حل کردن مسئله در ما وجود داشته باشد. بدون داشتن میلی شدید به حل مسئله دشوار، بخت در رسیدن به جواب آن یار ما نخواهد شد.
هر نظر، پبشنهاد و انتقادی دارین خوشحال میشم بدونم :) ممنونم که خوندین ^_^
مطلبی دیگر از این انتشارات
30 درسی که من از کار کردن و محیط کار یاد گرفتم.
مطلبی دیگر از این انتشارات
خاطرات یک آپارتمان نشین از یک منطقه متراکم و یک کوچه متراکم تر
مطلبی دیگر از این انتشارات
آموزش ماشین لرنینگ با پایتون ( پارت چهارم- matplotlib)