معماری تمیز؛ ترجیح یا ضرورت؟

اندکی بعد از این‌که به دنیای برنامه‌نویسی وارد شدم، صدایی را در درونم احساس کردم که همواره مرا به «تمیز و مرتب بودن» دعوت می‌کرد. برای این‌که این ندای درونی را بی‌پاسخ نگذارم، سعی می‌کردم در انتخاب نام متغیرها وسواس به خرج دهم ۱. اما بعد از مدتی متوجه شدم که این همهٔ آن چیزی نیست که آن ندای درونی از من درخواست می‌کند!

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

یک روز به طور تصادفی با کتابی برخوردم که به طور مفصل به Design Patternها پرداخته بود. آن زمان‌ واژه Design برای من فقط در زمینه UI معنی پیدا می‌کرد. بنابراین با هدف این‌که بتوانم رابط کاربری بهتری برای برنامه‌هایم طراحی کنم، خواندن این کتاب را آغاز کردم. اما هنگامی که متوجه شدم موضوع کتاب ارتباطی با UI ندارد، دوباره یاد آن ندای درونی افتادم ۲.

گاهی ساعت‌ها فکر می‌کردم که فلان قسمت را چطور بنویسم که در آینده هم بتوانم از آن استفاده کنم. بارها کدها را حذف می‌کردم و از نو می‌نوشتم تا آن ندای درونی آرام شود. اما نمی‌شد! ساختار لجوج و بَدْقِلِق اندروید هم مزید بر علت شده بود که آن ندای درونی رهایم نکند. تا این‌که یک روز با «عمو باب» آشنا شدم. عمو باب که یکی از نویسندگان بیانه توسعه چابک می‌باشد، مطلبی نوشته که به نظر می‌رسد سرآغاز موضوع Clean Architecture یا معماری تمیز باشد. کمی بعد متوجه شدم بسیاری از سوالاتی را که آن ندای درونی مطرح می‌کرد، می‌توانم با معماری تمیز پاسخ دهم.

تعریف معماری نرم‌افزار

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

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

معماری؛ ترجیح یا ضرورت؟

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

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

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

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

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

نظافت در معماری!

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

معماری تمیز از ساختار لایه‌ای بهره می‌گیرد. برخلاف معماری‌های سنتی لایه‌ای، معماری تمیز بر مبنای لایه داده استوار نبوده و پایگاه‌داده-محور نیست. در Clean Architecture، نرم‌افزار بر پایه قوانین کسب‌وکار بنا می‌شود و اصل بر این است که فریمورک‌ها، UI و پایگاه داده را از دید کدهای اصلی برنامه مخفی نگهداریم.

دستاوردها

با پیروی از قواعد معماری تمیز، نرم‌افزاری خواهیم داشت که ضمن برآوردن نیازمندی‌های کسب‌وکار، از ویژگی‌های زیر برخوردار است:

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

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

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

  • مستقل بودن از مرزهای سیستم: همه عناصر خارجی نرم‌افزار (همچون UI و پایگاه داده) بدون تاثیر روی هسته اصلی (قواعد کسب‌وکار) قابل تعویض هستند.

جمع‌بندی

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

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


پانوشت

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

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