علیرضا ارومند
علیرضا ارومند
خواندن ۱۰ دقیقه·۵ سال پیش

فصل اول Clean Architecture - طراحی و معماری چیست؟

1. مقدمه:

با شنیدن واژه‌های معماری و طراحی ممکن است معانی بسیار گسترده‌ای به ذهنمان رسوخ کند. دو کلمه‌ای که علی رغم استفاده زیاد در دنیای نرم‌افزار شاید به درستی درک نشده باشند. به واقع طراحی چیست؟ معماری چطور؟ تفاوت بین معماری و طراحی چیست؟

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

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

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

به گفته دیگر در این نقشه‌ها تمامی جزئیات که برای ایجاد یک خانه کامل مورد نیاز است و در کنار هم یک کل را تشکیل می‌دهند مشخص است. کاملا مشخص است که تصمیات جزئی مثل محل قرارگیری کلید و پریز و مفاهیم کلی مثل محل قرارگیری دیوارها و ستون‌ها چگونه در کنار هم یک ساختمان را می‌سازند.

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

2. آشنایی با اهداف:

اما اهداف این جریان تصمیمات چیست؟ هدف از یک طراحی خوب نرم‌افزار چیست؟ هدف از معماری تمیز و خوب نرم‌افزار چیزی بیشتر از رسیدن به تعریف آرمانگرایانه زیر نیست:

هدف از یک معماری نرم‌افزار به حداقل رساندن سرمایه انسانی مورد نیاز برای تولید و نگهداری نرم‌افزار است

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

3. یک مثال واقعی:

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

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

رشد تعداد نیرو‌های یک شرکت پیشرو در صنعت نرم‌افزار
رشد تعداد نیرو‌های یک شرکت پیشرو در صنعت نرم‌افزار

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

بهره‌وری در همان شرکت در همان بازه زمانی
بهره‌وری در همان شرکت در همان بازه زمانی

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

هنوز در بخش خوب ماجرا هستیم و قصه‌های دهشتناک‌تری در راه است. بیاید با هم نگاهی به هزینه تولید هر خط کد در این بازه زمانی بیاندازیم.

هزینه تولید هر خط کد در همین بازه زمانی
هزینه تولید هر خط کد در همین بازه زمانی

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

چه چیزی موجب این تغییر غیرقابل باورد در بهره‌وری شده است؟ چرا هزینه تولید 1 خط کد در هشتمین ریلیز بیش از 40 برابر اولین ریلیز نرم‌افزار شده است؟ ( البته این موارد برای خارجی‌ها غیرقابل باوره، برای ما خاطره است. ما از یه کامیت تا کامیت بعدی هزینه‌هامون 3 برابر میشه، ریلیز که خیلی بازه زمانی زیادیه)

3.1. ردپای آشفتگی:

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

در تصویر بعد شما نحوه تغییر بهره‌وری توسعه دهنده‌ها را مشاهده می‌کنید. در ابتدای کار بهره‌وری توسعه دهندگان 100% بوده و به مرور از بهره‌وری افراد کاسته شده و با کمی دقت می‌توانیم مشاهده کنیم که در چهارمین خروجی بهره‌وری تقریبا به صفر رسیده است.

نسبت بهره‌وری با هر ریلیز
نسبت بهره‌وری با هر ریلیز

از منظر توسعه‌دهندگان این نمودار نا‌امید کننده است. با اینکه هیچ کس تلاشش را کم نکرده و همه به سختی کار می‌کنند، اما بهره‌وری نابود شده است.

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

3.2. بیچاره مالکان شرکت:

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

نمودار رشد ماهانه هزینه حقوق کارکنان
نمودار رشد ماهانه هزینه حقوق کارکنان

نسخه اولیه با هزینه ماهانه چند صد هزار دلاری به دست آمده است. برای انتشار دوم و سوم چندصدهزار دلار به هزینه‌ها اضافه شده است. در پنجمین ریلیز هزینه‌های ماهانه 5 میلیون دلار اضافه شده است.برای ششمین ریلیز 10 میلیون، هفتمین ریلیز 14 میلیون و هشتمین ریلیز 20 میلیون دلار هزینه اضافه‌تر نسبت به اولین ریلیز داشته است.

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

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

اما چه کاری باید انجام شود؟ اصلا چه اشتباهی رخ داده است؟ چه مشکلی اینطور باعث کاهش بهره‌وری شده است؟ مدیران و مالکان کسب و کار چه کاری به جز داد و فریاد از ظلمی که توسط تیم توسعه به آن‌ها شده، می‌توانند انجام دهند؟

3.3. اشتباه کار کجاست؟

بیش از 2600 سال از زمانی که ازوپ نویسنده یونانی، افسانه لاک‌پشت و خرگوش را به تحریر درآورده می‌گذرد. نکات اخلاقی این داستان را بار‌ها و بارها شنیده اید:

رهرو آن نیست که گه تند و گهی خسته رود!
رهرو آن نیست که گه تند و گهی خسته رود!

آهستگی و پیوستگی رمز پیروزی در مسابقه است

همیشه سریع‌ترین‌ها و قوی‌ترین‌ها پیروز نیستند.

هرچه بیشتر عجله کنیم دیر‌تر به مقصد می‌رسیم( عجله کار شیطونه)

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

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

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

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

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

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

آشفتگی در کار همیشه کند‌تر از یک کار تمیز و بدون ایراد است. اهمیتی ندارد که این آشفتگی کوتاه مدت باشد یا بلند مدت.

برای اینکه بدانیم اثر کار تمیز به چه اندازه است خوب است نگاهی به نتایج آزمایشی که آقای Json Gorman انجام داده است بیاندازیم. او در طی 6 روز یک برنامه ثابت برای تبدیل اعداد به معادل یونانی‌ آن‌ها را توسعه داده است. شرط او برای پایان یافتن توسعه برنامه پاس شدن تمام تست‌های پذیرش بوده است. هر روز چیزی کمتر از 30 دقیقه برای انجام این کار زمان صرف شده است. در روز‌های فرد از روش TDD برای توسعه استفاده شده و در روز‌های زوج بدون TDD کار انجام شده است و نتیجه را در تصویر زیر مشاهده می‌کنید.

نتیجه تست آقای Json Gorman
نتیجه تست آقای Json Gorman


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

به عنوان یک توسعه دهنده باید همیشه به یاد داشته باشیم:

تنها راه افزایش سرعت این است که کارها را به درستی انجام دهیم.

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

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

4. جمع‌بندی:

در هر شرایطی بهترین راه برای موفقیت تیم‌های توسعه نرم‌افزار تشخیص اعتماد به نفس‌های کاذب و رفع آن‌ها است و تمرکز بر این مسئله که کیفیت جدی‌ترین مسئله تولید نرم‌افزار است.

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



clean codeclean architecturesoftware designsoftware architecturetdd
شاید از این پست‌ها خوشتان بیاید