چگونه اصول سالید را در ری اکت پیاده سازی کنیم؟ (بخش اول)

سلام.احتمالا به عنوان یک برنامه نویس ری اکت، اسم سالید به گوش تون خورده. درواقع تو مصاحبه یا آگهی های استخدامی بعضا باهاش برخورد کردید. اگرم تاحالا به گوش تون نخورده، احتمالا این دغدغه رو دارید که چطوری میشه استاندارد کدنویسی مو بالاتر ببرم، یا کدهای بهتری بنویسم. بخصوص اگه بخواید فریلنسری با سایت های خارجی کار کنید یا فکر مهاجرت کاری تو سرتونه، استفاده از این اصول توی کدنویسی تون خیلی مهمه. اگر دوست دارید این اصول رو یاد بگیرید من سعی کردم به زبون خودمونی و تا جای ممکن سطح پایین توضیحش بدم. ادامه مطلب رو از دست ندید. برای اینکه مطلب طولانی و خسته کننده نشه، دو تا بخشش کردم، حتما هر دو بخش رو مطالعه کنید.کلمه Solid مخفف 5 اصل اساسی در برنامه نویسی شی گراس که به شما کمک می کنه کدای واضح تر، انعطاف پذیرتر و قابل نگهداری تر (!) بنویسید. اینور اونور زیاد شنیدم که میگن ری اکت یه کتابخونه فانکشناله. و شاید در نگاه اول این طور به نظر برسه که باید بین ری اکت و مفاهیم شی گرایی دیوار کشید! ولی این درست نیست. درواقع پیاده سازی اصول و مفاهیم شی گرایی داخل ری اکت جی اس، نرمال و خیلی وقتا ضروریه. یکی از همین اصول سالیده. بخصوص الان که دیگه مد شده همه با تایپ اسکریپت کد می زنن و باکلاس شدن و اینا، رعایت یه سری اصول، روز به روز مهم تر میشه.اگه solid رو سرچ کنید مثال ها و توضیحات اصول سالید رو بیشتر داخل زبان های جاوا یا پایتون می بینید. واسه ی من که تجربه برنامه نویسی جاوا نداشتم درکش سخت بود، واسه همین تصمیم گرفتم یه خلاصه طور براساس برداشتم از پیاده سازی این اصول داخل ری اکت جمع بندی کنم.اول یه خلاصه ای بکنیم بعد هر کدومو توضیح می دم. کلمه SOLID مخفف 5 تا اصله:1. Single responsibility principle :به زبون ری اکتی میگه که هر کامپوننت یا تابع شما، باید فقط باید مسئول انجام یه کار باشه. یعنی قیمه ها رو نریزی تو ماستا. قیمه تو ظرف جدا باشه ماست هم تو ظرف جدا. کنار هم میذاری سر سفره2. Open/Closed Principle:یه کامپوننت یا تابع باید به گونه ای نوشته بشه که اگه خواستیم توسعه اش بدیم بتونیم این کارو با اضافه کردن کد جدید انجام بدیم. این میشه اُپن بودنش. کلوز بودنش هم به این معنیه که برا توسعه دادنش نباید مجبور بشیم کدای قبلی بیس رو تغییر بدیم. یعنی دستمون برا اضافه کردن چیز جدید بازه ولی برا تغییر دادن کامپوننت های بیس قبلی بستس.3. Liskov Substitution Principle :لیسکوف میگه که تابعا و کامپوننتا باید جوری طراحی بشن که اگه از یک کامپوننت دیگه ارث بری می کنن، این ارث بری اونقدر جامع باشد، که بشه کامپوننت زیرمجموعه (subtype) رو به سادگی جایگزین کامپوننت اصلی (supertype) کرد. یعنی بچه باید جوری ارث ببره از باباش که وقتی بچه رو می بینی انگار باباشو دیدی!4. Interface Segregation Principle :اینم میخواد بگه که کامپوننتا و توابع، نباید وابسته به متدها و پراپس هایی باشن که از اونا استفاده نمی کنن. به زبون شیرین ری اکتی اینطوریه که میگه، دیتای اضافه هل نده بره تو کامپوننت. فقط چیزایی که لازمه رو بفرست. مثلا از یه آبجکت دیتا، فقط یه پراپرتی ایمیل می خوای، کل آبجکتو پراپس نکن تو یه کامپوننت، بعد تو کامپوننت بخوای ایمیل شو جدا کنی، از همون اول فقط ایمیل رو بده بره تو کامپوننت.5. Dependency Inversion Principle :مورد آخر یه خورده پیچیده اس. درواقع یه جورایی مربوط به اصل اوله ولی یه کم فرق داره. درواقع میخواد بگه که یه کامپوننت نباید به کامپوننت هم سطح خودش وابسته باشه. بلکه این وابستگی باید به یک کامپوننت بالاتر و جامع تر منتقل بشه. یعنی چی؟ بعدا مفصل توضیح میدم.اصل تک وظیفه ای بودن (Single responsibility principle)قرار شد که هر کامپوننتی که می نویسیم مسئول یه چیز باشه فقط. اگه فانکشنالیتی های مختلف تو یه کامپوننت تعریف کردی، بیا اینا رو جدا جدا کن. خوردش کن. این میشه اصل اول. خب حالا فایده اش چیه؟اولا نگهداری و توسعه کد راحت تره. دوما خطایابیش ساده تره. سوما کد خواناتره. چهارما ری یوزبل تره. وقتی تیکه تیکه باشه کدت، می تونی اگه لازم شد یه تیکه شو جا دیگه هم ادرس بدی استفاده کنی. مثلا کد زیر رو ببین.برای مثال این بخش یه کد خیلی ساده با چت جی پی تی جنریت کردم. به این صورت که یه لیست از ماشین ها رو از یه ای پی آیی می گیره. بعد هم لیست می کنه زیرهم. یه سلکت هم بالا سرش داره که می تونی براساس رنگ ماشین ها، لیست رو فیلتر کنی.این کد اصل اول رو رعایت نکرده. در واقعا داخل این کامپوننت ما چندتا کار رو داریم انجام میدیم. طبق اصل اول هر کدوم از این کارا باید بره تو یه کامپوننت جدا.مثلا فچ زدن و گرفتن دیتا رو ببری تو یه فایل جدا، تابع فیلترینگ و سلکت رو ببری تو یه فایل جدا، جدولت رو هم تو یه فایل جدا. بعد همشو توی یه فایل اصلی صدا بزنی.کدشو نمی نویسم دیگه. طولانی میشه. مطلبو بگیرید کافیه. اگه بلد نیستین، به چت جی پی تی بگید براتون اسپلیتش کنه. نتونستی، بهم تو کامنتا بگو تا کدشو بزارم. نکته ای که باید همیشه تو ذهنتون باشه اینه که تا جای ممکن هر فانکشنالیتی ای که می تونید رو سعی کنید جدا کنید. حالا نه اینکه هر چیزی رو خورد خورد کنید. مثلا لزومی نداره که جدول تون رو هدرش رو یه کامپوننت کنید و سطرهای داخلش رو یه کامپوننت (البته بعضی جاها شاید لازم باشه همین کارم بکنید اما اینجا چون فانکشنالیتی خاصی روی جزئیات جدول نداریم، پس جدا کردنش کار بیهوده ایه). جوری توابع رو جدا کنید که هر کامپوننت یه کار مجزا رو مستقل انجام بده. یه نیم نگاهی هم داشته باشید به اینکه اگه نیاز شد بعدا بتونید از اون کامپوننتی که جدا کردید جای دیگه هم استفاده کنید (reusable). چراغ بندازید با دقت ببینید کامپوننت تون چندتا کار داره انجام میده. اگه بیشتر از یکی بود، باید خوردش کنید.اصل باز/ بسته بودن (Open/Closed Principle)همونطور که اول کار اشاره کردم، برای اضافه کردن فیچر جدید نباید مجبور شیم توابع یا کامپوننت هایی که قبلا نوشته بودیم و به عنوان بیس داریم ازشون استفاده می کنیم رو تغییر بدیم. بلکه باید اونجایی که داریم استفاده می کنیم فقط تغییرات بدیم. یه مثال می زنم که روشن بشه.فرض کنید برا یه پروژه ای یه کامپوننت کاستومایز کردید برا دکمه. اسمش هم هست IconButton. می تونه مثلا این شکلی باشه:یه نکته تو پرانتز بگم، دوتا آیکن من از پکیج heroicons ایمپورت و استفاده کردم اینجا. کارکردش هم مشخصه دیگه. شما یه باتن نوشتی که هرجا خواستی صداش بزنی، یه تکست بش میدی و یه تایپ و یه تابع برا آن کلیکش. میاد تکست رو میذاره وسط دکمه و براساس تایپش هم یه آیکن میذاره جلوی تکست.مثلا اینجوری صداش می زنیم:حالا ببینیم ایراد اینجور نوشتن چیه. ایرادش اینه که اگه مثلا یه دکمه دانلود هم خواستی اضافه کنی که آیکنش مثلا آیکن دانلود باشه، باید بیای یه تایپ جدید و یه آیکن جدید اضافه کنی به کامپوننت IconButton . هر سری که بخوای یه تایپ جدید اضافه کنی مجبوری این کد رو تغییر بدی. که این نقض اصل دومه.چجوری درستش کنیم؟ خیلی ساده. به جا اینکه تایپ رو پراپس کنی، خود آیکن رو پراپس کن. اینجوری دیگه مجبور نیستی تو این کامپوننت چیزی رو تغییر بدی، هرجا کامپوننت باتن رو صدا زدی، هر آیکنی خواستی پراپس می کنی می فرستی داخل. یعنی الان کامپوننت IconButton اینجوری میشه:خواستی هم صداش بزنی اینجوری میشه:اینجوری کدت وابسته به نوع آیکن نیست، هر آیکنی خواستی پاس می دی میره داخل کامپوننت و اونجا فقط استایلشو مشخص کردی. گرفتین مطلبو؟ دیگه قرار نیست کامپوننت بیس آیکن باتن رو تغییر بدیم. فقط جایی که داریم صداش می زنیم تغییر می کنه.اصل جایگزینی لیسکوف (Liskov Substitution Principle)یه راست میرم سر مثال. اونجا متوجه می شید داستان چیهفرض بگیرید یه کامپوننت نوشتین برا اینپوت سرچ. مثلا این شکلی:تو این کامپوننت ما از یه کامپوننت بیسیک آشنا به نام input استفاده کردیم تا یه ورژن پیشرفته ازش بسازیم به نام سرچ اینپوت. این کامپوننت کاستومایز شده شامل یک آیکن و یه سری استایل دلخواه، نسبت به حالت اینپوت پیور هست. خب ظاهرا که مشکلی نیست. درسته؟ یه کم بیشتر فکر کنید......فهمیدین ایراد کار کجاست؟ مشکل اینه که اینجوری که ما پراپس دادیم به اینپوت، بخش زیادی از پراپس ها و اتریبیوت های ممکن رو از دست دادیم! یعنی چی؟شما در حالت عادی به اینپوت می تونی اتریبیوت های مختلف بدی (اینجا رو ببین)، مثلا disabled، maxlength، pattern، size و ... . اما الان اگه اینا رو بدی به کامپوننت searchInput که کامپوننت subtype ما هست، چون پراپس هاش تعریف نشده برای input داخلش (کامپوننت supertype) بنابراین عمل نمی کنه. در واقع ما همه ویژگی های اینپوت رو نتونستیم منتقل کنیم به کامپوننت searchInput.حالا چجوری درستش کنیم؟اینجوری:به همین راحتی. درواقع میایم میگیم که هرچی searchInput به عنوان پراپس گرفت، اونو ببر بده به اینپوت. و این وسط هر پراپسی که جزو اتریبیوت های اینپوت باشه مجازه. دیگه لازم نیست دونه دونه مشخصشون کنیم. بنابراین دستمون بازه که اتریبیوت های اینپوت رو به سرچ اینپوت بدیم.خب! مرسی که تا اینجا با من همراه بودین. سه تا از اصول رو گفتیم. دوتای دیگه اش می مونه. که توی پست بعدی میگم براتون. از اینجا می تونید ادامه شو بخونید. کامنت و اشتراک گذاری فراموش نشه. مرسی بچه هافعلا،بدرود.