۲۴ آذر ۱۴۰۴

Techboy

اخبار و اطلاعات روز تکنولوژی

پنج روشی که کد شما به هم پیوست می‌شود، چه خوب و چه بد.

درک پنج نوع هم‌بستگی ایستا به شما کمک می‌کند تا عمیق‌تر به کد خود و نحوهٔ کارکرد آن نگاه کنید – و ببینید چگونه می‌توانید آن را بهبود بخشید.

درک پنج نوع هم‌بستگی ایستا به شما کمک می‌کند تا عمیق‌تر به کد خود و نحوهٔ کارکرد آن نگاه کنید – و ببینید چگونه می‌توانید آن را بهبود بخشید.

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

البته، ماژول‌های کد باید به نوعی به هم متصل باشند تا هر چیزی کار کند. عبارت «کم‌هم‌بستگی» نشان می‌دهد که می‌خواهیم کد کمتر به هم متصل باشد نه بیشتر. اما چگونه می‌توانیم این را اندازه‌گیری کنیم؟ چگونه می‌توانیم درباره درجه‌ی هم‌بستگی کد فکر کنیم؟ بسیاری از جزئیاتی که در اینجا به آن‌ها می‌پردازم احتمالاً واضح به نظر می‌رسند—بخش زیادی از آن‌ها حکم حکمت عمومی توسعه‌دهندگان است—اما من طبقه‌بندی کاننسنس را روشن‌کننده می‌دانم. این می‌تواند بینش‌های شگفت‌انگیزی در مورد چگونگی ترکیب کد ما آشکار کند.

دو نوع کاننسنس وجود دارد—ساکن و پویا. کاننسنس ساکن می‌تواند با بررسی بصری کد شما کشف شود، در حالی که کاننسنس پویا فقط با اجرای کد شما کشف می‌شود. این هفته به کاننسنس ساکن می‌پردازم و هفتهٔ بعد به کاننسنس پویا می‌پردازم.

پنج نوع کاننسنس ساکن وجود دارد. شناخت و درک آن‌ها می‌تواند به شما کمک کند عمیق‌تر به کد و عملکرد آن نگاه کنید. بسیاری و شاید همهٔ آن‌ها برای شما آشناست، اگرچه شرط می‌بندم که تا به حال آن‌ها را به عنوان «هم‌بستگی» در نظر نگرفته‌اید.

کاننسنس نام

کاننسنس نام زمانی رخ می‌دهد که دو چیز باید دربارهٔ نام یک مورد به توافق برسند. این ضعیف‌ترین شکل کاننسنس، یا شل‌ترین شکل هم‌بستگی است و چیزی است که باید سعی کنیم به آن محدود ourselves. اگر یک رویه مانند زیر اعلان کنید

function DoSomething(): void { // Code that does something }

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

کاننسنس نوع

کاننسنس نوع زمانی رخ می‌دهد که دو موجود باید دربارهٔ نوع یک مورد به توافق برسند.

مشخص‌ترین مثال پارامترهای یک متد است. اگر یک تابع را به شکل زیر اعلان کنید:

class SomeClass { processWidget(aWidget: Widget, aAction: WidgetActionType): boolean { // Function logic goes here return false; // Example return value } }

در این صورت هر کد فراخوانی‌کننده باید یک Widget و یک WidgetActionType را به عنوان پارامترهای تابع processWidget ارسال کند و باید یک boolean را به عنوان نوع نتیجه بپذیرد.

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

کاننسنس معنا

کاننسنس معنا زمانی رخ می‌دهد که مؤلفه‌ها باید دربارهٔ معنای مقادیر خاصی به توافق برسند. کاننسنس معنا اغلب زمانی رخ می‌دهد که از «اعداد جادویی» استفاده می‌کنیم، یعنی زمانی که مقادیر خاصی که در چندین مکان معنا دارند، به کار می‌روند.

کد زیر را در نظر بگیرید:

function getWidgetType(aWidget: Widget): number { if (aWidget.status === 'Working') { return 1; } else if (aWidget.status === 'Broken') { return 2; } else if (aWidget.state === 'Missing') { return 3; } else { return 0; } }

اگر می‌خواهید از کد بالا استفاده کنید، باید معنای کد نتیجه برای تابع GetWidgetType را بدانید. اگر یکی از کدهای نتیجه (۱، ۲، ۳ یا ۰) را تغییر دهید یا کد جدیدی اضافه کنید، باید کدی را که از این تابع استفاده می‌کند در همه مکان‌ها به‌روز کنید. و برای انجام این تغییر باید معنای هر کد نتیجه را بدانید. البته می‌توانید به این تابع نگاه کنید و بفهمید که ‘Working’ برابر ۱ است، اما برای فراخوانندهٔ تابع این به‌وضوح واضح نیست، درست است؟

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

کاننسنس موقعیت

کاننسنس موقعیت زمانی رخ می‌دهد که کد در دو مکان مختلف باید دربارهٔ موقعیت موارد به توافق برسد. این معمولاً در فهرست پارامترها رخ می‌دهد که ترتیب پارامترها توسط متد الزامی است. اگر یک پارامتر را در وسط فهرست پارامترهای موجود اضافه کنید، همهٔ استفاده‌های آن متد باید پارامتر جدید را در موقعیت صحیح اضافه کنند.

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

در اینجا یک مثال است. این روتین را در نظر بگیرید:

class UserManager { addUser(aFirstName: string, aLastName: string, aAge: number, aBirthdate: Date, aAddress: Address, aPrivileges: Privileges): void { // add the user here } }

ما می‌توانیم کاننسنس یا هم‌بستگی را با بازسازی این کاننسنس موقعیت به استفاده از کاننسنس نوع کاهش دهیم. به عنوان مثال:

type UserRecord = { firstName: string; lastName: string; age: number; birthday: Date; address: Address; privileges: Privileges; }; class UserManager { addUser(aUser: UserRecord): void { // add user here } }

در اینجا با ایجاد یک نوع واحد و وابسته کردن رویهٔ addUser به نوع یک پارامتر به‌جای موقعیت‌های فهرست طولانی پارامترها، هم‌بستگی را کاهش دادیم. می‌توانید داده‌های UserRecord را به هر ترتیبی که می‌خواهید پر کنید و این کار بار شناختی فراخوانی تابع addUser را کاهش می‌دهد.

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

کاننسنس الگوریتم

کاننسنس الگوریتم زمانی رخ می‌دهد که دو ماژول باید دربارهٔ الگوریتم خاصی برای عملکرد مشترک به توافق برسند.

تصور کنید یک سرور با API زبان C# می‌سازید که توسط یک کلاینت TypeScript مصرف می‌شود. اطلاعاتی که بین این دو ماژول ارسال می‌شود حساس است و باید رمزگذاری شود. بنابراین، این دو ماژول توسط کاننسنس الگوریتم به هم متصل می‌شوند زیرا هر دو باید بر روی الگوریتم رمزگذاری مورد استفاده توافق کنند. اگر الگوریتم رمزگذاری برای سرور تغییر کند، باید برای کلاینت نیز تغییر یابد.

کاهش کاننسنس الگوریتم می‌تواند دشوار باشد، زیرا اغلب دارای درجهٔ بالایی از محلی‌سازی است (یعنی هم‌بستگی در ماژول‌هایی که منطقی یا فیزیکی دور هستند رخ می‌دهد). یک راه حل ممکن این است که یک ماژول سوم ایجاد کنید که مکان واحدی برای یافتن الگوریتم باشد و ماژول‌های سرور و کلاینت از آن ماژول سوم استفاده کنند. در این حالت، سرویسی سوم ایجاد می‌کنید که تمام رمزگذاری را در یک مکان مدیریت می‌کند.

حدس من این است که با تمام این موقعیت‌ها برخورد کرده‌اید و به‌صورت شهودی روش صحیح بازسازی را درک کرده‌اید، با پیروی از اصول شناخته‌شده‌ای مانند «خودت را تکرار نکن» و «هرگز از اعداد جادویی استفاده نکن». اما اغلب، هم‌بستگی کد شما ظریف‌تر و دشوارتر برای مشاهده است نسبت به مسائلی که این عبارات به آن‌ها می‌پردازند. در این موارد، درک کاننسنس ساکن می‌تواند به شما کمک کند کدی تمیزتر و کمتر هم‌بسته بنویسید.