Amir Mokarchi
Amir Mokarchi
خواندن ۵ دقیقه·۴ سال پیش

هنر تبدیل 6 خط کد به 92 خط کد

مطمئناً ، if-else و switch کدهای متراکم و ساده را ایجاد می کند. اما نرم افزار شما نباید از کمترین خط ممکن تشکیل شود ، که maintainability ، readability یا flexibility را از بین ببرد.

من بخش زیادی از تقسیم‌بندی کد را می‌بینم که بر روی enum ها یا دیگر مقادیر گسسته اتفاق می‌افتد. برخی از توسعه دهندگان حتی زمانی که به آن‌ها گفته می‌شود از if-then-else استفاده نکنند وضعیت را وخیم تر می کنند.

اما ، به نظر شما عواقب استفاده از enum در عبارت if-then-else چیست؟

انشعاب بر روی مقادیر گسسته ، تغییر نرم افزار شما را دشوار می کند. هر ویژگی جدید شما را ملزم می کند تا محل انشعاب را ردیابی کنید و کد موجود خود را متناسب با آن اصلاح کنید.

قطعاً اینگونه نیست که ما می خواهیم یک نرم افزار عالی بسازیم. این شاید اولین گام عالی برای کارکرد کد شما باشد. اما ، همانطور که به سمت بهبود کد خود پیشرفت می کنید ، switch و if-then-else باید دیگر از بین رفته باشند.

روش سنتی انشعاب سازی با استفاده از if-else و switch منسوخ شده است. این SOLID نیست. انعطاف پذیر نیست

بگذارید من این موضوع را تجسم کنم
فرض کنید که شما با توجه به دلایلی باید راهی برای به روز رسانی کاربران داشته باشید. برای سادگی، یک کاربر تنها دو دلیل دارد که در سیستم شما به روز می‌شود.

تغییر آدرس برای تغییر آدرس در سیستم CRM باید به بازاریابی اطلاع داده شود.

تغییر نام کاربری (1) دنبال کنندگان کاربر باید در مورد تغییر نام کاربری مطلع شوند- (2) url slug کاربر باید به روز شود.

شما این دو مورد ساده را در قطعه کد زیر پیاده سازی می کنید.

یک ثانیه وقت بگذارید و این کد ضعیف طراحی شده را بخوانید. بدون شک بسیاری از توسعه دهندگان ارشد نسبت به این مساله کابوس می‌بینند و ممکن است یک محرک استرس پس از حادثه (PTSD) تلقی شوند.

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

تنها نکته خوبی که می توان در مورد این کد گفت ، تلاش برای ایجاد یک الگوی طراحی نیمه CQS گونه است.

اگر تمایل شما این است که بگویید "این باید یک switch باشد!" باید لحظه ای فکر کنید و در مورد آنچه در توسعه نرم افزار مهم است تأمل کنید.

شما تمام مدت با الزامات جدید برخورد خواهید کرد.

بگویید که الزامات شما حالا این شکلی هستند.

فعال سازی تایید دو مرحله ای و تغییر ایمیل هم باید باعث بروزرسانی کاربر شود.

سوال این است که آیا شما واقعا قصد دارید این دو دلیل جدید را برای به روز رسانی یک کاربر با اضافه کردن مقادیر اضافه enum و اضافه کردن دو else-if اجرا کنید؟

اگر تصمیم بگیرید که از راه اشتباهی پیش بروید ، در اینجا به نظر می رسد. این کد بخوبی خوانده نمی شود

علاوه بر اینکه به طورم مداوم نیاز به افزودن شاخه‌های اضافی هستید - که به خودی خود یک عمل سوال‌برانگیز است - هر زمان که باید debug یا یک bugfix را انجام دهید، شما این کار را با کد کاملا بی‌ربط احاطه شده انجام می دهید.

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

بیایید نگاهی بیندازیم که چگونه می توانید از رویکردهای زننده مانند این جلوگیری کنید.

بازسازی (Refactoring) برای اجرای polymorphic بسیار حیرت انگیز است

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

قبلاً اشاره کردم ما می توانیم خیلی بهتر عمل کنیم. منظور من از بهتر نوشتن، کدی است که 1) قابل خواندن ، 2) قابل نگهداری و 3) انعطاف پذیر باشد.

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

شما خواهید دید که ما تا چه حد می‌توانیم بدون if-then-else و یا switch پیش برویم.

اکنون UpdateAsync به همین سادگی تبدیل شده است.

Simplified UpdateAsync method implementation
Simplified UpdateAsync method implementation

توجه داشته باشید که چگونه اکنون به جای enum یک آرگومان اینترفیس می گیرید. اکنون ، این متد مسئولیت دانستن نحوه انجام به روزرسانی را به یک شی specialized خاص تفویض می کند.

پیاده سازی های IUpdateReason به این شکل است. من جزئیات مربوط به arguments سازنده و اجرای متد را به تخیل شما می سپارم.

UpdateReason interface and its concrete implementations
UpdateReason interface and its concrete implementations

هر کلاس کاملا با نیازمندی‌ها همسو است و آن را مدیریت می‌کند. Debugging ، fixing bugs، و testing اکنون بسیار آسان‌تر از مقایسه با رویکرد منسوخ افتضاح است.

در این حالت ، هر نیاز جدید منجر به یک کلاس specialized می شود.کد شما اکنون شی گرا است و نگهداری آن بسیار آسان است. کارت عالی بود.

اما یک مسئله نهایی وجود دارد

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

منطقی است که در این حالتcommand objects و command handlers ایجاد کنید.این کد فراخوانی را ساده می کند ، زیرا فقط یک command مانند UpdateUserAddress ارسال می کند و handler's action مربوطه فراخوانی می شود.

و در نهایت

به طور خلاصه if-then-else و switch کد شما را به طور قابل توجهی دشوارتر برای خواندن ، نگهداری و تنظیم می کند. دفعه بعدی که در حین اجرای یک ویژگی با استفاده از انشعاب سنتی چند منظوره قرار گرفتید ، لحظه ای وقت بگذارید و تحلیل کنید که چگونه می توانید از polymorphism و رویکردهای مدرن استفاده کنید.

best practicessoftware developmentprogrammingrefactoringcsharp
DotNet Developer
شاید از این پست‌ها خوشتان بیاید