در مقاله قبلی پیچیدگی نرم افزار رو بحث کردیم و در این مقاله انسجام رو میخواهیم برسی کنیم، این مباحث یکم سخت هست ولی در صورت درکش یه بیس تئوری قوی خواهد بود برامون پس بهتر هست چند بار مرور بشه.
پیچیدگی کامپوننت، واحد اندازاه گیری انسجام، به مقدار انسجام زیر مجومعه های یک کامپوننت میگیم. انسجام یعنی برای یک وظیفه و در راستای یک هدف خدمت کردن به عبارتی تک وظیفه بودن هست انسجام یعنی هر چقدر یک کامپوننت یک کار انجام دهد همان اندازه هم انسجام بالایی دارد، تک وظیفه بودن یعنی انسجام میخاد بگه کارهای متفاوت رو در قسمت های متفاوت انجام بده و برعکس کارهای عین هم رو در یک جا انجام بده، به عبارتی مفهوم Separation of concerns رو تعریف میکنه.
کامپوننت هایی که انسجام بیشتری دارند چند ویژگی اصلی دارند.
از دل انسجام قانون تک وظیفه میاد بیرون، یعنی پدری که اومده قانون سولید نوشته و گفته تک وظیفه بودن یک اصل هست سرخورد ننوشته پشتش یه فلسفه قوی هست که انسجام اونو توضیح میده، باز از پایین آوردن پیچیدگی بحث میکنه کوهیژن و میگه اگر جایی که من باشم اونجا دیگه پیچیده نیست، در مقاله قبلی دیدیم که نرم افزار پیچیده هست، این اصل میگه من میتونم مشکل پیچیدگی رو تا حد زیادی حلش بکنم، توی برنامه نویسی شی گرا از قابل استفاده مجدد بحث میکنه باز کوهیژن اونم ارضا میکنه و در نهایت هزینه نگهداری و خوانا بودن که یکی از اصل های کد تمیز هست رو هم ارضا میکنه.
High-cohesion Or strong-cohesion
انسجام قوی یا انسجام بالا زمانی اتفاق می افتد که تمامی زیر مجموعه های یک کامپوننت اعم از کلاس ها، فانکشن ها، سطرها یک کار انجام بدهند و یک هدف داشته باشند.یک فانکشن یا کلاس هر چقدر کار کمی انجام دهد میشه گفت به همون اندازه انسجام بالایی دارد.
نکته: منظور از داشتن کد کمتر در یک کلاس یا متد مفهومی هست گاها صد سطر هست گاها یک سطر هست ولی باید طوری باشد که قابل کپی پیست کردن نباشد یعنی با کپی پیست به جایی دیگه قابل انتقال نباشد.
وقتی این رو به طور کامل درک کنیم متوجه میشیم میکروسرویس ها دلیل خلق شدنشون همین مورد هست و کسی که اولین بار میکروسرویس رو به دنیا معرفی کرد چیز جدیدی رو نیاورده فقط این مفهموم رو در لایه طراحی اینترپرایز پیاده کرده.
Low-cohesion Or Weak-cohesion
انسجام ضعیف یا پایین، در حقیقت عکس موارد بالا منجر میشه انسجام بیاد پایین، توی دنیای واقعی هم شاید شنیده باشید میگن یه چاه پر عمق بهتر از یه دریای کم عمق هست، یه تخصص رو بخون و توش ارشد شو، نه که از هر چیزی یه مقدار بدونی. وقتی ماشین کامپیوترش ایراد پیدا میکنه میبری به مکانیک میگه ببر به برق کار وقتی پیش اون میبری میگه ببر پیش کسی که از ECU سر دربیاره میخام بگم توی دنیای واقعی هم حل مشکلات به صورت درست حسابی به دست کسانی باز میشه که توی اون مورد تک وظیفه هستن.
در دنیای توسعه شاید کلاس های یوتیلتی دیده باشید، به نظر من خجالت آورتر از کلاس های یوتیلتی در یک پروژه نداریم، این کلاس رو باز میکنن و همه چیز توش مینویسن و بدترش کلاس رو سراسری میکنن از همه جای پروژه در دسترس هست اینقدر توش کد و کارهای متفاوت انجام میشه که بعضا وقتی میبینم میگم یه متد main میذاشتی و پروژه رو از اینجا اجرا میکردی چه کاری هست به نوشتن لایه های دیگه، این برادر کلا شی گرا رو اشتباه متوجه شده و بویی از تک وظیفه بودن نبرده!!
وقتی از واحد بودن یا وحدانیت خدا هم بحث میکنیم همینه غیر این نیست، خدا چون واحد هست منسجم هست، غیر قابل کپی هست، وحدت در کثرت یا کثرت در وحدت رو نمیخام باز کنم ولی این کانسپت کوهیژن از دل طبیعت هستی میاد بیرون چون خالق خودش واحد هست.
logical
دوستان وقتی از انسجام بحث میکینم منظور انسجام از لحاظ منطقی نیست، یعنی یه کلاس خواندن درست بکن توش از فایل بخونه از دیتابیس بخونه از API بخونه!! بله خیلی گوش نواز هست ولی وقتی از انسجام صحبت میشه چنین چیزی نیست و بنده دیدم افرادی رو که این مدلی کد زدن و دلیلشونم این بوده که کار خواندن رو یک جا انجام میده خیر داری اشتباه میزنی، گرچه این کلاس فقط کارش خوندن هست ولی داره از دنیاهای مختلف ریسورس های مختلف رو میخونه و درستش اینه خواندن فایل داخل کامپوننت فایل باشه. یه جایی میگیم کلاس برش رو بنویس و دوستمون برش لباس، مو، صدا،راه و... توی یک کلاس نوشته مگه داریم همچین چیزی آخه!! وقتی میپرسی میگه اما کارش برش هست!! دوست عزیز وقتی از انسجام بحث میکنیم باید به طبیعت کار نگاه کنی برش صدا با برش مو یه چیزی نیست و تنها تو کلمه برش اشتراک دارند!!
منظور شباهت اسمی دلیل نمیشه داخل یه کلاس باشند، گفتم که انتزاعی هست مفاهیم و باید خیلی زیاد روش وقت گذاشت و اندیشه کرد و الا کلاس برش یه روزی سرتم خواهد برید با این فرمون بری جلو!!
Temporal
یه جایی برنامه نویس میخاد کار موقتی انجام بده و بلوک کد رو داخل یه کنترل خطا میندازه وقتی با خطا مواجه شد یه لاگ مینویسه یا یه رفتاری انجام میده، دقت کنید این نوع اشتباه هم خیلی ظریف هست چون استدلالش اینه رفتار مربوط به این کلاس هست پس باید اینجا ارضا کنم!! ولی کنترل خطا یا نوشتن به دیتابیس یا تغیر فایل چیزی نیست که در یک جا باشند اینا کلا موجودیت های متفاوتی هستند و باید جداگانه به دست گرفته بشند و یکی باشه کارش فقط کنترل استثنا باشه و یک جا باشه همه جا کپی پیست نشه مرکزی بشه تا انسجام بره بالا. به نظر میاد این دوستمون هیچ چیزی از cross cutting concerns نمی دونه.
Procedural
اشتباه بعدی هم که بیشتر دیده میشه رویه های هست یه فانکشن نوشته داخلش احراز هویت میکنه بعدش قبل احراز دیتای اومده رو ولیدیت میکنه توکن میسازه ، پسورد ریست میکنه!!!
Communicational / Informational
این مدل اشتباه هم یکم معصوم تر از دیگری هست برنامه نویس در مورد ارتباط همه چیز رو داخل یه کلاس انجام میده مثلا ارسال و دریافت داده و پردازش دیتای اومده یا کنترل Time out ها و یا ارسال دوباره یا اتصال دوباره ....
Sequential
اینم که با پیشرفت کردن سینتکس های زبان های برنامه نویسی این روزها زیاد دارم میبینم به جاهایی که مشاوره میدم، خروجی یه فانکشتن رو به ورودی فانکشن دیگه میده و این تو در تویی تا چندین سطر میره وقتی میپرسم چرا اینکارو میکنی میگه میخام داخل یک سطر یه کار انجام بشه!! برادر نکن اینکارو به کی میگی به چی میگی!! احتمالا اگر سینتکس اجازه بده دوستمون کل کلاس رو تو یک سطر مینوشت و اگوش ارضا میشد، فکر میکنه اینجوری بنویسه خفنتر دیده میشه، وقتیم ایراد میگیرم به کدش شاکی میشه و فکر میکنه دارم حسادت میکنم...
نکته: اگر داخل یک متد بین کد اگر فاصله میگذارید یعنی دارید داخل یک متد دوکار انجام میدین و اونجا کوهیژن پایین هست! ولی دلیل نمیشه ورودی یه کلاس رو به یه کلاس یا متد دیگه تو در تو تا انتها بدی و دلیلت این باشه میخام خط فاصله نگذارم تا کوهیژن بره بالا!!
Functional
در بین این موارد بالا از همه بهتر بابع گرا هست، تک هست خیلی خوب تعریف شده و تا جای ممکن کار کم یا وظیفه کمی انجام میده. بهترین مدل از انسجام هست.
نرم افزار روز به روز در حال تغیر و بزرگ شدن هست وقتی متدهای تک وظیفه درست تعریف کنیم و بنویسیم ، درخواست های جدید تاثیری روی این متد ها نخواهد گذاشت بلکه متد های جدیدی نوشته میشه.
اگر کد بالا رو بخایم بررسی کنیم یه کلاس ایمیل نوشته برنامه نویس وقتی نگاه میکنیم خیلی ظریف و معصوم دیده میشه و تمام ها کارهای مربوط به پرینت رو یکجا داره انجام میده... در کورس کلین کد و آرشیتکت اینارو کامل بررسی میکنیم و میگیم که چیکار باید کنیم در چنین مواردی..
کد بالا رو بخواهیم برسی کنیم میتونیم بپرسیم تو این سیستم فقط کاستومر لاگ اوت میکنه؟ به غیر این کس دیگه لاگ اوت نمیکنه؟!! ربطی به این کلاس نداره چرا آورده اینجا!! یا داره پسورد رو ولیدیت میکنه یا عوض میکنه! باید به ازای هر تیپ کاربر جدا جدا ریست پسورد بنویسیم؟!! اینا اشتباهاتی هست که در دنیای برنامه نویسی زیاد میبینم و این مدل کد نویسی ها کوهیژن رو به شدت میارن پایین و پیچیدگی رو میبرن بالا.
این دو کلاس رو نگاه کنید، کدام کوهیژن بالایی دارد؟!! ابتدا به نظر میاد کلاس A کوهیژن بالایی دارد ولی یکم روش فکر کنیم میگیم بین سه فانکشن کلاس A هیچ اشتراکی وجود ندارد و میتونیم هر کدام رو جدا جدا در یه کلاس بنویسم یعنی کوهیژن پایینی دارد ولی کلاس B رو نمیتونی به این راحتی از هم جدا کنی و گذشته از اون تمام کارهایی گه کلاس آ انجام میده رو خود ب هم قادر به انجامش هست و سوال این میشه دلیل چرایی وجود کلاس آ چی هست؟ داخل یک فایل باشند !! این مثال یکم سخت هس درکش ولی مجبور میکنه به فکر کردن مار!!
به نظر شما مشکل این کد بالا چیست؟ شاید بگید برادر شمام اذیت نکن بنده خدا کلا پنج خط کد نوشته دیگه چیکار باید بکنه تا راضی بشی؟ ولی دوستان این برنامه نویس گناهکار هست داره چندین کارو یک جا انجام میده ابتدا ولیدیشن انجام میده دوما کنترل استثنا هم میکنه سوما داره کار لاگ هم انجام میده!! اینجوری که توی عکس دیده میشه نیست این دوستان پس فردا پروژه بزرگ بشه این کلاس چند صد خط خواهد شد و بدتر اینکه از روی کانتکس رشته داره شرط برسی میکنه، این برنامه نویس رو باید.....
در مقاله بعدی شروع میکنیم با برسی قوانین سولید.