معماری تمیز (Clean Architecture)
در دنیای نرم افزار، قانونی نانوشته وجود دارد که هر مهندس با تجربه ای دیر یا زود با آن روبرو می شود: «هر کدی که امروز می نویسید، فردا یک بدهی فنی است، مگر اینکه برای تغییر طراحی شده باشد.» بسیاری از تیم های فنی در شروع راه، با سرعتی باورنکردنی حرکت می کنند. فیچرها یکی پس از دیگری پیاده می شوند، ساختار دیتابیس به سرعت طراحی می شود و همه چیز در یک معماری یکپارچه و به هم تنیده جمع می شود. اما پس از گذشت زمانی اندک، زمانی که نیاز به تغییر در یک منطق تجاری ساده پیش می آید، کل سیستم مانند خانه ای پوشالی فرو می ریزد. این همان لحظه ای است که بدهی فنی، نرخ بهره سنگین خود را از شما طلب می کند؛ جایی که هزینه نگهداری و اصلاح کد، از هزینه توسعه اولیه آن پیشی می گیرد.
واقعیت تلخ این است که بسیاری از پروژه های نرم افزاری نه به دلیل نبود دانش فنی، بلکه به دلیل «فقدان چارچوب فکری برای مدیریت تغییر» شکست می خورند. وقتی کدها به هم جوش خورده باشند و لایه های سیستم از یکدیگر تفکیک نشده باشند، هر تغییر کوچکی می تواند منجر به بروز خطاهایی در بخش هایی شود که انتظارش را ندارید. این وضعیت، ناشی از نادیده گرفتن اصول بنیادی در طراحی است که در نهایت منجر به فلج شدن تیم توسعه و کاهش کیفیت محصول نهایی می شود.
در این مقاله، قصد ندارم تنها تعاریف آکادمیک را بازگو کنم یا به مفاهیم تکراری بپردازم. هدف من در این متن، ترسیم نقشه راهی برای عبور از آشفتگی کدهای قدیمی و رسیدن به ساختاری است که نه تنها در برابر تغییرات مقاوم باشد، بلکه رشد و توسعه آن با همان سرعت و دقت روزهای اول پروژه همراه باشد. ما قرار است درباره معماری تمیز صحبت کنیم؛ فلسفه ای که دیتابیس، رابط کاربری و فریم ورک ها را به عنوان جزئیات پیاده سازی می بیند، نه ستون های اصلی برنامه. اگر به دنبال ساخت بنایی هستید که در برابر فشار ترافیک و نیازهای پیچیده بیزینس تاب بیاورد، این مقاله برای شما نوشته شده است.
کالبدشکافی بحران؛ چرا معماری های سنتی شکست می خورند؟
بسیاری از معماران نرم افزار، وقتی از شکست یک پروژه سخن می گویند، به اشتباه انگشت اتهام را به سمت تکنولوژی اشتباه یا عدم مهارت تیم در کدنویسی می گیرند. اما واقعیت این است که در نود درصد موارد، مشکل نه در ابزار، بلکه در «انتخاب ساختار» نهفته است. بیایید معماری سنتی لایه ای (Layered Architecture) را که دهه ها به عنوان استاندارد شناخته می شد، زیر تیغ جراحی ببریم.
۱. توهم جداسازی در لایه های سنتی
در مدل لایه ای کلاسیک، ما سیستم را به سه لایه اصلی تقسیم می کنیم: ارائه (Presentation)، منطق تجاری (Business Logic) و دسترسی به داده (Data Access). در نگاه اول، این تفکیک بسیار تمیز به نظر می رسد. لایه Presentation با کاربر صحبت می کند، لایه Business محاسبات را انجام می دهد و لایه Data Access با دیتابیس در تماس است.
اما ایراد بزرگ کجاست؟ در این مدل، لایه Business به طور مستقیم به لایه Data Access وابسته است. به عبارت دیگر، بیزینس شما «می داند» که دیتابیس شما SQL Server است. این یعنی اگر روزی تصمیم بگیرید دیتابیس خود را به MongoDB تغییر دهید یا از یک سرویس خارجی برای تامین داده استفاده کنید، باید دست به قلب منطق تجاری خود ببرید. این وابستگی عرضی، بزرگ ترین عامل بروز «بدهی فنی» است. کد شما به جای آنکه با «نیازهای بیزینس» همسو باشد، با «ساختار دیتابیس» همسو شده است.
۲. دیتابیس؛ دیکتاتور پنهان در پروژه های بزرگ
در معماری های رایج، دیتابیس نقش «مرکز هستی» را بازی می کند. تمام پروژه ها با طراحی جداول دیتابیس شروع می شوند. ERD طراحی می شود، کلیدهای خارجی تعریف می شوند و سپس کد برنامه حول این ساختار ساخته می شود. این رویکرد، دیتابیس را به یک دیکتاتور تبدیل می کند.
وقتی منطق تجاری شما بر اساس جداول دیتابیس شکل می گیرد، شما عملا در حال کدنویسی برای «ذخیره سازی» هستید، نه برای «حل مسئله ی بیزینس». این وضعیت باعث می شود که با گذشت زمان، منطق بیزینس در لایه های پایین سیستم نشت کند. مثلا کدهای مربوط به فیلتر کردن داده ها به جای اینکه در دامنه (Domain) باشد، در کوئری های غول پیکر SQL پراکنده می شود. نتیجه؟ کدی که نه تست پذیر است و نه قابل تغییر.
۳. جفت شدگی (Coupling) و اثر دومینویی
وقتی لایه ها به هم وابستگی مستقیم دارند، هر تغییر کوچکی در لایه داده، به لایه بیزینس سرایت می کند و به لایه ارائه می رسد. در پروژه های کوچک، این موضوع شاید اهمیتی نداشته باشد، اما در مقیاس بزرگ، شما با یک «اثر دومینویی» روبرو هستید. تغییری که باید ده دقیقه زمان ببرد، به دلیل وابستگی های متقابل، به چند روز کار پرخطر و تست های سنگین تبدیل می شود.
این همان جایی است که سرعت توسعه به شدت افت می کند. تیم شما به جای اضافه کردن فیچرهای جدید، در حال دست و پنجه نرم کردن با باگ هایی است که ناشی از تغییر در لایه های غیرمرتبط ایجاد شده اند. ما این را «بدهی فنی انباشته» می نامیم. معماری سنتی، شما را مجبور می کند که برای هر تغییر ساده، کل سیستم را در نظر بگیرید.
۴. چرا توسعه دهندگان از این بحران فرار نمی کنند؟
شاید بپرسید اگر این معماری ناقص است، چرا همه از آن استفاده می کنند؟ پاسخ ساده است: «سادگی گول زننده». پیاده سازی معماری لایه ای در ابتدا بسیار ساده است و نیاز به دانش پیچیده ی الگویی ندارد. اما «سادگی اولیه» قیمت سنگینی دارد. این هزینه ای است که در میان مدت و بلندمدت پرداخت می شود. بسیاری از توسعه دهندگان به دلیل فشار زمانی و ددلاین های پروژه، «میان بر» می زنند و در نهایت در تله ی وابستگی های غیرمنطقی گیر می کنند.
ادامه مقاله در