این نسخه صوتی با کمک هوش مصنوعی تولید شده، پس ممکنه گاهی تپق یا اشکالات کوچیکی داشته باشه.
شغل «معمار نرمافزار» (software architect) اغلب در صدر فهرست بهترین شغلها در سراسر جهان قرار دارد. اما وقتی خوانندگان به شغلهای دیگر موجود در این فهرستها نگاه میکنند (مثل پرستار حرفهای یا مدیر مالی)، مسیر شغلی مشخص و روشنی برای آنها وجود دارد. پس چرا برای معماران نرمافزار چنین مسیری وجود ندارد؟
اول از همه، این صنعت تعریف مشخص و خوبی از «معماری نرمافزار» (software architecture) ارائه نداده است. وقتی در کلاسهای پایه این حوزه تدریس میکنیم، دانشجویان اغلب درخواست یک تعریف دقیق از اینکه معمار نرمافزار چه کاری انجام میدهد، دارند — و ما قاطعانه از دادن چنین تعریفی خودداری کردهایم. و ما تنها کسانی نیستیم که اینطور عمل میکنیم. در مقالهی معروفش با عنوان «چه کسی به یک معمار نیاز دارد؟», «مارتین فاولر» (Martin Fowler) هم معروف است که از تعریف کردن این نقش سر باز زده و بهجای آن به نقلقول معروفی بسنده کرده:
«معماری یعنی چیزهای مهم... هر چیزی که باشند.»
— رالف جانسون (Ralph Johnson)
وقتی از ما اصرار شد، نمودار ذهنیای (mindmap) را تهیه کردیم که در شکل ۱-۱ (Figure 1-1) نشان داده شده — که هرچند ناقص است، اما تا حدی دامنهی معماری نرمافزار را مشخص میکند. در ادامه بهزودی تعریف خودمان از معماری نرمافزار را ارائه خواهیم داد.
دوم اینکه، همانطور که در نمودار ذهنی هم نشان داده شده، نقش معمار نرمافزار حجم گستردهای از مسئولیتها را در بر میگیرد که به طور مداوم نیز در حال گسترش است. ده سال پیش، معماران نرمافزار صرفاً با جنبههای فنی معماری مثل ماژولار بودن (modularity)، اجزاء (components) و الگوها (patterns) سروکار داشتند. اما از آن زمان تاکنون، به دلیل ظهور سبکهای جدید معماری که قابلیتهای بیشتری را پوشش میدهند (مثل معماری مبتنی بر مایکروسرویسها - microservices)، نقش معمار نرمافزار نیز گسترش یافته است. در ادامه، ما به بررسی تقاطعهای مختلف بین معماری و دیگر بخشهای سازمان خواهیم پرداخت که در بخش «تقاطع معماری و...» آمده است.

سوم اینکه، معماری نرمافزار یک هدف متحرک و در حال تغییر مداوم است، و دلیل آن هم اکوسیستم توسعهی نرمافزار است که با سرعت بالایی در حال تحول است. هر تعریفی که امروز ارائه شود، بهاحتمال زیاد ظرف چند سال آینده منسوخ خواهد شد. تعریف ارائهشده در ویکیپدیا از معماری نرمافزار یک دید کلی قابلقبول ارائه میدهد، اما بسیاری از جملات آن دیگر بهروز نیستند؛ مثلاً این جمله:
«معماری نرمافزار دربارهی تصمیمگیریهای ساختاری بنیادینی است که پس از اجرا، تغییرشان هزینهبر است.»
اما معماران نرمافزار امروزی سبکهایی مثل مایکروسرویسها (microservices) را طراحی کردهاند با در نظر گرفتن اصل «توسعه تدریجی» (incremental development)، به طوری که دیگر تغییرات ساختاری در آنها هزینهبر نیست. البته چنین قابلیتی، بهای خودش را هم دارد؛ مثلاً ممکن است باعث افزایش وابستگی بین اجزا (coupling) شود.
بسیاری از کتابهای معماری نرمافزار به آن بهچشم یک مسألهی ایستا نگاه میکنند؛ انگار که وقتی یکبار حل شد، دیگر میتوان آن را کنار گذاشت. اما ما در این کتاب به ذات پویا و متغیر معماری نرمافزار — حتی در خود تعریف آن — اذعان میکنیم و آن را در سراسر کتاب لحاظ کردهایم.
چهارم، بخش بزرگی از مطالب موجود دربارهی معماری نرمافزار فقط ارزش تاریخی دارند. خوانندگان صفحهی ویکیپدیا احتمالاً با انبوهی از مخففها (acronyms) و ارجاعات متقاطع به دنیای گستردهای از دانش مواجه میشوند که ممکن است گیجکننده باشد. با این حال، بسیاری از این مخففها نمایانگر تلاشهای قدیمی و بعضاً شکستخورده هستند. حتی راهحلهایی که چند سال پیش کاملاً منطقی بودند، ممکن است امروز جواب ندهند، چون بستر و زمینه (context) تغییر کرده است. تاریخ معماری نرمافزار پر است از چیزهایی که معماران امتحان کردند و بعدها متوجه اثرات منفی آن شدند. ما در این کتاب، بسیاری از این درسها را مرور میکنیم.
دامنهی معماری نرمافزار تنها بخشی از دنیای توسعهی نرمافزار نیست که دائماً در حال تغییره. فناوریهای جدید، تکنیکهای نو، قابلیتهای تازه... در واقع پیدا کردن چیزهایی که تغییر نکردن در دههی گذشته راحتتر از لیست کردن تمام چیزهایی هست که تغییر کردهان.
معماران نرمافزار باید در دل همین اکوسیستم در حال تغییر، تصمیمگیری کنن. چون همهچیز در حال تغییره — حتی پایههایی که مبنای تصمیمگیریهامون هستن — لازمه که معماران بعضی از اصول و فرضیات اساسی گذشته رو دوباره بررسی کنن. مثلاً کتابهای قبلی دربارهی معماری نرمافزار اصلاً تأثیر DevOps (فرهنگ و مجموعهای از ابزارها و فرآیندهایی برای خودکارسازی توسعه و عملیات نرمافزار) رو در نظر نگرفته بودن، چون در زمان نوشتن اون کتابها DevOps اصلاً وجود نداشت.
وقتی کسی معماری رو مطالعه میکنه، باید در نظر داشته باشه که، مثل خیلی از هنرها، معماری هم فقط در بستر خودش قابل درکه. خیلی از تصمیمهایی که معماران گذشته گرفتن، بر اساس واقعیتهای محیطی بوده که توش قرار داشتن. مثلاً یکی از اهداف اصلی معماری نرمافزار در اواخر قرن بیستم این بود که بیشترین بهرهبرداری ممکن از منابع مشترک انجام بشه؛ چون تمام زیرساختها تو اون زمان گرون و تجاری بودن — مثل سیستمعاملها، اپلیکیشن سرورها، سرورهای دیتابیس و غیره.
فرض کن سال ۲۰۰۲ وارد یه دیتاسنتر بشی و به مدیر عملیات بگی:
«یه ایدهی انقلابی دارم برای طراحی معماری که توش هر سرویس روی ماشین جداگانهی خودش اجرا میشه و هر کدوم هم دیتابیس مخصوص خودش رو داره» (یعنی همون چیزی که الان بهش میگیم مایکروسرویسها - microservices). بعد بگی:
«پس برای این کار به ۵۰ لایسنس ویندوز، ۳۰ تا لایسنس اپلیکیشن سرور، و حداقل ۵۰ لایسنس دیتابیس سرور نیاز دارم.»
در سال ۲۰۰۲، ساختن یه معماری مثل مایکروسرویسها از نظر اقتصادی کاملاً غیرقابلتصور بود. ولی حالا، با ظهور نرمافزار متنباز (open source) و همچنین شیوههای نوین مهندسی نرمافزار که با انقلاب DevOps همراه بوده، ما میتونیم چنین معماریای رو بهطور معقول و عملی پیادهسازی کنیم.
پس یادت باشه: هر معماریای محصول بستر و زمان خودش هست.
کل صنعت فناوری اطلاعات مدتهاست که برای ارائهی یک تعریف دقیق از «معماری نرمافزار» با چالش مواجهه.
بعضی از معمارها از معماری نرمافزار بهعنوان نقشهی کلی سیستم (blueprint) یاد میکنن، و بعضی دیگه اون رو نقشهی راه توسعهی سیستم (roadmap) میدونن.
اما مشکل این تعاریف رایج اینه که دقیقاً مشخص نمیکنن نقشهی کلی یا نقشهی راه شامل چه چیزیه؟
مثلاً وقتی یک معمار، معماری یک سیستم رو «تحلیل» میکنه، دقیقاً چی رو تحلیل میکنه؟
شکل ۱-۲ (Figure 1-2) راهی برای درک معماری نرمافزار رو نشون میده.
در این تعریف، معماری نرمافزار از چند بخش کلیدی تشکیل شده:

ساختار سیستم (structure of the system)، همانطور که در شکل ۱-۳ (Figure 1-3) نشان داده شده، اشاره دارد به نوع سبک معماری (architecture style) یا سبکهایی که سیستم با استفاده از آنها پیادهسازی شده — مثل مایکروسرویسها (microservices)، لایهای (layered architecture)، یا ریزهستهای (microkernel architecture).
اما توصیف یک معماری صرفاً از طریق ساختار آن، نمیتواند درک کاملی از معماری را ارائه دهد.
مثلاً فرض کن از یک معمار خواسته بشه که معماری یک سیستم رو توصیف کنه و او در پاسخ بگه:
«این معماری، مایکروسرویسیه.»
در اینجا، اون معمار فقط داره به ساختار سیستم اشاره میکنه — نه خود معماری.
برای درک کامل معماری یک سیستم، باید علاوه بر ساختار، اطلاعاتی دربارهی ویژگیهای معماری (architecture characteristics)، تصمیمات معماری (architecture decisions)، و اصول طراحی (design principles) هم داشته باشیم.

ویژگیهای معماری (architecture characteristics) بُعد دیگری از تعریف معماری نرمافزار رو تشکیل میدن (نگاه کنید به شکل ۱-۴).
این ویژگیها، در واقع معیارهای موفقیت یک سیستم رو مشخص میکنن — که معمولاً مستقل از عملکرد (functionality) خود سیستم هستن.
توجه داشته باشید که تمام ویژگیهای معماری که در این بخش اشاره شده، بدون نیاز به آگاهی از منطق عملکردی سیستم قابل بررسی هستن، اما با این حال، وجود اونها برای عملکرد صحیح سیستم ضروریه.
ویژگیهای معماری تا حدی مهم هستن که نویسندگان این کتاب چندین فصل رو به بررسی و تعریف دقیق اونها اختصاص دادن.

عامل بعدی که معماری نرمافزار رو تعریف میکنه، تصمیمات معماری (architecture decisions) هست.
تصمیمات معماری، قوانینی رو مشخص میکنن که بر اساس اونها باید سیستم ساخته بشه.
برای مثال، یک معمار ممکنه تصمیم بگیره که در یک معماری لایهای (layered architecture)، فقط لایههای منطق کسبوکار (business layer) و سرویسها (services layer) اجازه دسترسی به پایگاه داده رو داشته باشن (نگاه کنید به شکل ۱-۵)،
و لایهی نمایش (presentation layer) مجاز نباشه مستقیماً با دیتابیس ارتباط برقرار کنه.
در واقع، تصمیمات معماری محدودیتها و قواعد حاکم بر سیستم رو تعریف میکنن و به تیمهای توسعه میگن چه کاری مجازه و چه کاری مجاز نیست.

اگر یک تصمیم معماری خاص به دلیل شرایط یا محدودیتهای خاصی در بخشی از سیستم قابل اجرا نباشه، اون تصمیم (یا قانون) میتونه از طریق چیزی به نام انحراف (variance) شکسته بشه.
بیشتر سازمانها مدلهایی برای مدیریت این انحرافها دارن که توسط هیئت بازبینی معماری (Architecture Review Board - ARB) یا معمار ارشد (chief architect) بررسی میشن.
این مدلها، فرآیند رسمیای رو برای درخواست انحراف از یک استاندارد یا تصمیم معماری خاص فراهم میکنن.
در این حالت، استثنا بودنِ یک تصمیم معماری خاص توسط ARB (یا معمار ارشد، در صورتی که ARB وجود نداشته باشه) بررسی میشه، و با توجه به توجیهها و ملاحظات مربوط به مزایا و معایب (trade-offs)، یا تأیید میشه یا رد.
آخرین عامل در تعریف معماری نرمافزار، اصول طراحی (design principles) هست.
اصل طراحی با تصمیم معماری فرق داره؛ چون اصل طراحی یک راهنما (guideline) هست، نه یک قانون سختگیرانه و الزامی.
برای مثال، اصل طراحی نشوندادهشده در شکل ۱-۶ (Figure 1-6) توصیه میکنه که تیمهای توسعه از پیامرسانی غیرهمزمان (asynchronous messaging) بین سرویسها در معماری مایکروسرویسی استفاده کنن تا عملکرد سیستم افزایش پیدا کنه.
تصمیمهای معماری (که بهنوعی قوانین هستن) نمیتونن تمام شرایط و گزینههای ممکن برای ارتباط بین سرویسها رو پوشش بدن.
به همین خاطر، اصول طراحی میتونن بهعنوان راهنمای کلی در انتخاب رویکردهای مناسب (در این مثال: پیامرسانی غیرهمزمان) عمل کنن، و در عین حال دست توسعهدهنده رو باز بذارن تا بسته به شرایط خاص، پروتکل ارتباطی مناسبتری مثل REST یا gRPC رو انتخاب کنه.

تعریف نقش معمار نرمافزار تقریباً به همون اندازهای دشواره که تعریف «معماری نرمافزار» سخته.
این نقش میتونه از یک برنامهنویس متخصص (expert programmer) تا فردی که مسیر فنی استراتژیک شرکت رو تعیین میکنه، گسترده باشه.
بهجای اینکه وقت رو صرف کاری کنیم که نتیجهای نداره — یعنی تلاش برای ارائهی تعریفی دقیق از این نقش — بهتره تمرکز رو بذاریم روی انتظاراتی که از یک معمار نرمافزار وجود داره.
صرفنظر از عنوان شغلی یا شرح وظایف رسمی، هشت انتظار کلیدی از هر معمار نرمافزار وجود داره:
اولین کلید موفقیت و اثربخشی در نقش معمار نرمافزار، درک و تمرین همین هشت انتظار اصلیه.
از یک معمار انتظار میره که تصمیمات معماری و اصول طراحی لازم برای هدایت تصمیمات فناوری در سطح تیم، دپارتمان یا کل سازمان رو تعریف کنه.
در این انتظار، واژهی کلیدی، "هدایت" (guide) هست.
یک معمار باید راهنما باشه، نه اینکه مستقیماً انتخاب فناوری رو مشخص کنه.
برای مثال، فرض کن یک معمار تصمیم بگیره که از React.js برای توسعهی رابط کاربری استفاده بشه.
در این حالت، معمار داره تصمیم فنی میگیره، نه تصمیم معماری یا اصل طراحی که به تیم کمک کنه خودش گزینهها رو انتخاب کنه.
در عوض، معمار بهتره به تیمهای توسعه این راهنمایی رو بده که برای توسعهی فرانتاند از فریمورک مبتنی بر معماری reactive استفاده کنن.
به این ترتیب، تیم میتونه بین گزینههایی مثل Angular، Elm، React.js، Vue یا سایر فریمورکهای reactive تصمیم بگیره — یعنی انتخاب با تیم باقی میمونه، اما در یک مسیر مشخص و هدایتشده.
هدایت انتخابهای فناوری از طریق تصمیمات معماری و اصول طراحی، کار آسونی نیست.
نکتهی کلیدی اینه که از خودمون بپرسیم:
«آیا این تصمیم معماری، تیم رو در انتخاب فنی درست راهنمایی میکنه، یا اینکه مستقیماً انتخاب فنی رو انجام داده؟»
البته گاهی وقتها لازمه که یک معمار تصمیم فنی خاصی هم بگیره — مثلاً برای حفظ یک ویژگی معماری مهم مثل مقیاسپذیری (scalability)، عملکرد (performance) یا در دسترسبودن (availability).
در این صورت، حتی اگر تصمیم شامل انتخاب فناوری خاص باشه، باز هم تصمیم معماری محسوب میشه، چون برای حفظ ویژگیهای معماری اتخاذ شده.
این مرز بین تصمیم فنی و تصمیم معماری اغلب گمراهکنندهست و معمارها باهاش دستوپنجه نرم میکنن — به همین خاطر، فصل ۱۹ این کتاب کاملاً به تصمیمات معماری اختصاص داده شده.
از یک معمار انتظار میره که بهطور مداوم معماری سیستم و محیط فناوری فعلی رو تحلیل کنه و در صورت لزوم، راهکارهایی برای بهبود ارائه بده.
این انتظار، به چیزی اشاره داره که بهش میگیم "زنده بودن معماری" (architecture vitality) — یعنی بررسی اینکه آیا معماریای که مثلاً سه سال پیش طراحی شده، امروز هم با توجه به تغییرات تجاری و فنی هنوز جواب میده یا نه.
تجربه ما نشون داده که تعداد زیادی از معمارها تمرکز کافی روی تحلیل مستمر معماری موجود ندارن.
نتیجهی این کمتوجهی، چیزی میشه که بهش میگیم فرسایش ساختاری (structural decay) — یعنی توسعهدهندهها در طول زمان تغییراتی در کد یا طراحی اعمال میکنن که باعث آسیبزدن به ویژگیهای حیاتی معماری میشن، مثل عملکرد، در دسترس بودن و مقیاسپذیری.
یکی دیگه از جنبههای فراموششدهی این انتظار، محیطهای تست و انتشار (release environments) هستن.
شاید چابکی در تغییر کد (code agility) خوب باشه، اما اگر تست تغییرات چند هفته طول بکشه و استقرار اونها چند ماه، اونوقت چابکی واقعی در معماری حاصل نمیشه.
از یک معمار انتظار میره که تغییرات در فناوری و حوزهی مسئله (problem domain) رو بهشکل جامع و کلنگرانه تحلیل کنه تا سازگاری و سلامت معماری رو ارزیابی کنه.
گرچه چنین چیزی بهندرت توی آگهیهای شغلی دیده میشه، اما برای اینکه اپلیکیشنها مرتبط و بهروز باقی بمونن، معمار باید این انتظار رو برآورده کنه.
از یک معمار انتظار میره که با جدیدترین فناوریها و روندهای صنعتی همگام بمونه.
توسعهدهندهها باید همیشه خودشون رو نسبت به فناوریهایی که هر روز باهاش کار میکنن بهروز نگه دارن تا مرتبط باقی بمونن (و در واقع شغلشون رو حفظ کنن!).
اما برای معمارها، این موضوع حتی حیاتیتره؛ چون تصمیماتی که یک معمار میگیره معمولاً طولعمر زیادی دارن و تغییر دادنشون دشواره.
آشنایی و پیگیری روندهای کلیدی باعث میشه که معمار بتونه برای آینده آماده بشه و تصمیمات درستی بگیره.
با این حال، ردیابی و همگام بودن با روندها برای یک معمار نرمافزار ساده نیست.
در فصل ۲۴ کتاب، به روشها و منابع مختلفی اشاره شده که به معمار کمک میکنن بتونه این کار رو بهتر انجام بده.
از یک معمار انتظار میره که اطمینان حاصل کنه تیمهای توسعه به تصمیمات معماری و اصول طراحی پایبند هستن.
تضمین پایبندی یعنی معمار باید بهطور مداوم بررسی کنه که آیا تیمهای توسعه، تصمیمات و اصولی رو که توسط معمار تعریف، مستندسازی و ابلاغ شده رعایت میکنن یا نه.
مثلاً فرض کن معمار تصمیم گرفته که توی یه معماری لایهای، فقط لایههای سرویس و منطق کسبوکار اجازه دسترسی مستقیم به دیتابیس رو داشته باشن، و لایهی نمایش (presentation layer) چنین دسترسیای نداشته باشه.
در نتیجه، برای سادهترین درخواست به دیتابیس، لایهی نمایش باید از کل معماری عبور کنه.
حالا تصور کن یک توسعهدهندهی رابط کاربری، برای بهبود عملکرد (performance)، تصمیم بگیره مستقیماً به دیتابیس یا لایهی ماندگاری (persistence layer) دسترسی پیدا کنه — برخلاف تصمیم معماری.
اما این تصمیم معماری بهدلیل خاصی گرفته شده بوده:
برای کنترل تغییرات.
وقتی لایهها بسته (closed) نگه داشته بشن، میشه بدون تأثیرگذاری روی لایهی نمایش، تغییراتی در دیتابیس ایجاد کرد.
اگر معمار نظارت و تضمین رعایت تصمیمات معماری رو جدی نگیره، چنین تخطیهایی بهراحتی اتفاق میافتن،
و در نتیجه، معماری نمیتونه ویژگیهای لازم («-ilities» مثل maintainability، scalability و...) رو برآورده کنه و سیستم طبق انتظار کار نخواهد کرد.
در فصل ۶، مفصلتر دربارهی اندازهگیری پایبندی از طریق توابع سلامت خودکار (automated fitness functions) و ابزارهای خودکار بحث شده.
از یک معمار نرمافزار انتظار میره که با مجموعهای متنوع از فناوریها، فریمورکها، پلتفرمها و محیطها آشنا باشه.
این به این معنی نیست که معمار باید در همهی این فناوریها متخصص باشه؛ بلکه باید در حد آشنایی مؤثر، با فناوریهای مختلف آشنا باشه.
امروزه بیشتر محیطهای نرمافزاری ناهمگون (heterogeneous) هستن — به این معنا که سیستمها و سرویسها از زبانها و فناوریهای مختلفی استفاده میکنن.
حداقل انتظار اینه که معمار بتونه با این سیستمها و سرویسها تعامل برقرار کنه، فارغ از اینکه با چه زبان یا پلتفرمی نوشته شدن.
یکی از بهترین روشها برای برآورده کردن این انتظار اینه که معمار از منطقهی راحتی خودش خارج بشه.
تمرکز روی یک فناوری یا پلتفرم خاص ممکنه امن و راحت باشه، ولی یک معمار مؤثر باید فعالانه دنبال کسب تجربه در زبانها، فناوریها و پلتفرمهای مختلف باشه.
راهکار خوب برای موفق شدن در این زمینه، تمرکز بر پهنای دانش فنی (technical breadth) بهجای عمق فنی (technical depth) صرف هست.
پهنای دانش فنی یعنی ترکیب مواردی که در موردشون اطلاعات کلی داری با مواردی که واقعاً در اونها متخصصی.
مثلاً، برای یک معمار خیلی ارزشمندتره که با ۱۰ محصول کشینگ مختلف آشنا باشه و مزایا و معایب هرکدوم رو بدونه، تا اینکه فقط در یک مورد از اونها متخصص باشه.
از یک معمار انتظار میره که تا حد قابل قبولی با دامنهی کسبوکار (business domain) مربوط به پروژه آشنا باشه.
معماران مؤثر فقط فناوری رو نمیفهمن، بلکه درک درستی از زمینهی کسبوکاری که سیستم در اون قرار داره هم دارن.
بدون دانش دامنهی کسبوکار، درک مسائل واقعی، اهداف تجاری، و نیازمندیها دشوار میشه — و در نتیجه طراحی معماری مؤثر هم ممکن نیست.
فرض کن معمار یک مؤسسه مالی بزرگ هستی ولی با اصطلاحاتی مثل "میانگین شاخص جهتدار" (average directional index)، قرارداد aleatory، بازارهای افزایشی (rates rally) یا بدهی غیر اولویتدار (nonpriority debt) آشنا نیستی.
در این صورت، نهتنها نمیتونی با ذینفعان (stakeholders) و کاربران کسبوکار بهدرستی ارتباط برقرار کنی، بلکه خیلی سریع اعتبارت رو از دست میدی.
موفقترین معمارهایی که ما میشناسیم، کسانی هستن که هم دانش فنی عملی و گسترده دارن و هم دانش قوی در یک دامنهی خاص.
این افراد میتونن با مدیران ارشد (C-level) و کاربران کسبوکار با زبان خودشون صحبت کنن — زبانی که برای اونها قابل فهم و مرتبطه.
همین توانایی ارتباطی باعث میشه که این معماران از نظر دیگران قابل اعتماد و حرفهای بهنظر برسن و تواناییشون در طراحی یک معماری مؤثر و صحیح تأیید بشه.
یک معمار نرمافزار (Software Architect) باید از مهارتهای بینفردی بسیار خوبی برخوردار باشد؛ از جمله توانایی کار تیمی، تسهیلگری (Facilitation)، و رهبری.
داشتن مهارتهای برجسته در زمینه رهبری و تعامل با دیگران برای اکثر توسعهدهندگان (Developers) و معماران نرمافزار، انتظار دشواری است. بهعنوان افرادی فنی، توسعهدهندگان و معماران بیشتر علاقهمندند مسائل فنی را حل کنند، نه مشکلات انسانی. با این حال، همانطور که جرالد واینبرگ (Gerald Weinberg) معروفاً گفته: «فرقی نمیکنه چی بهتون بگن، مشکل همیشه از نوع انسانی هست.»
از یک معمار انتظار میره که نهتنها راهنماییهای فنی به تیم ارائه بده، بلکه تیمهای توسعه رو در مسیر اجرای معماری هم رهبری کنه. مهارتهای رهبری دستکم نیمی از آن چیزیست که برای تبدیل شدن به یک معمار نرمافزار مؤثر نیازه، فارغ از اینکه نقش یا عنوان شغلی اون فرد چی باشه.
صنعت پر از معماران نرمافزار شده که برای تعداد محدودی موقعیت شغلی رقابت میکنن. داشتن مهارتهای قوی در زمینه رهبری و تعامل با دیگران، راهی خوب برای برجسته شدن در بین بقیه و ایجاد تمایز محسوب میشه. ما معماران زیادی رو دیدیم که از نظر فنی بسیار توانمند بودن، اما به دلیل ناتوانی در رهبری تیمها، راهنمایی و منتورینگ توسعهدهندهها و برقراری ارتباط مؤثر در بیان ایدهها و تصمیمات معماری، در کار خودشون ناموفق بودن. مشخصه که چنین افرادی در حفظ موقعیت یا شغل خودشون با مشکل روبرو میشن.
از یک معمار انتظار میره که فضای سیاسی سازمان رو درک کنه و بتونه در اون فضا حرکت مؤثری داشته باشه.
شاید عجیب به نظر برسه که در کتابی درباره معماری نرمافزار، درباره مذاکره و سیاستهای سازمانی صحبت میشه. اما برای روشن شدن اهمیت این مهارتها، بیاین یک سناریو رو بررسی کنیم:
فرض کنید یک توسعهدهنده تصمیم میگیره از strategy pattern (الگوی طراحی استراتژی، برای جداسازی رفتارها از کلاسها و کاهش پیچیدگی) استفاده کنه تا پیچیدگی چرخشی (Cyclomatic Complexity) یه بخش پیچیده از کد رو کاهش بده. کی واقعاً اهمیت میده؟ شاید اون توسعهدهنده بابت استفاده از این الگو مورد تحسین قرار بگیره، اما معمولاً نیازی به گرفتن تأییدیه برای چنین تصمیمی نیست.
حالا سناریویی رو در نظر بگیرین که یه معمار مسئول سیستم مدیریت ارتباط با مشتری (CRM) در شرکته. این معمار با چالشهایی مثل کنترل دسترسی دیتابیس از سمت سایر سیستمها، حفظ امنیت دادههای مشتری، و اعمال تغییرات در ساختار دیتابیس (Schema) مواجهه. دلیل اصلی هم اینه که سیستمهای زیادی مستقیماً به پایگاه داده CRM وصل شدن. بنابراین، معمار تصمیم میگیره چیزی به اسم application silos (جزایر دادهای، یعنی هر اپلیکیشن فقط به دیتابیس خودش دسترسی داره) ایجاد کنه.
با این تصمیم، معمار میتونه کنترل بیشتری روی دادههای مشتری، امنیت، و فرآیند تغییرات داشته باشه. اما بر خلاف مثال قبلی، این تصمیم تقریباً از طرف همهی شرکت مورد اعتراض قرار میگیره (بهجز تیم CRM البته!). سایر اپلیکیشنها به دادههای مدیریت مشتری نیاز دارن. حالا اگر دیگه نتونن مستقیماً به دیتابیس دسترسی داشته باشن، باید از طریق سیستم CRM اون دادهها رو بگیرن؛ یعنی با استفاده از روشهایی مثل REST، SOAP یا سایر پروتکلهای دسترسی از راه دور (Remote Access Protocols).
نکتهی اصلی اینه که تقریباً هر تصمیمی که یک معمار نرمافزار (Software Architect) میگیره، با چالش و مخالفت مواجه میشه.
تصمیمات معماری اغلب از طرف مالکان محصول (Product Owners)، مدیران پروژه (Project Managers)، و ذینفعان تجاری (Business Stakeholders) به دلیل افزایش هزینه یا زمان مورد انتقاد قرار میگیرن. از طرفی، این تصمیمات ممکنه از طرف توسعهدهندگانی که فکر میکنن روش خودشون بهتره هم به چالش کشیده بشه. در هر دو حالت، معمار باید بتونه در فضای سیاسی سازمان حرکت کنه و از مهارتهای پایهای مذاکره استفاده کنه تا بتونه تأییدیه برای تصمیمات خودش بگیره.
این موضوع میتونه برای یک معمار نرمافزار بسیار ناامیدکننده باشه، چون بیشتر تصمیماتی که در نقش توسعهدهنده میگرفته، نیازی به تأیید یا حتی بازبینی نداشته. جنبههایی مثل ساختار کد، طراحی کلاسها، انتخاب الگوهای طراحی (Design Patterns)، و حتی گاهی انتخاب زبان برنامهنویسی، همگی جزئی از هنر برنامهنویسی بهشمار میرن. اما حالا که معمار میتونه تصمیمات گسترده و مهمتری بگیره، باید برای تقریباً تمام اونها دلایل قانعکننده ارائه بده و از اون تصمیمات دفاع کنه.
مهارتهای مذاکره، درست مثل مهارتهای رهبری، اونقدر حیاتی و ضروری هستن که ما یک فصل کامل از این کتاب رو به درک این مهارتها اختصاص دادیم (نگاه کنید به فصل ۲۳).
در طول دههی گذشته، دامنهی معماری نرمافزار گسترش پیدا کرده و مسئولیتها و دیدگاههای بیشتری رو در بر گرفته. ده سال پیش، رابطهی معمول بین معماری و عملیات (Operations) رسمی و قراردادی بود، با مقدار زیادی بوروکراسی. بیشتر شرکتها برای اینکه با پیچیدگیهای میزبانی زیرساخت خودشون درگیر نشن، عملیات رو به شرکتهای شخص ثالث واگذار میکردن، اون هم با قراردادهایی شامل تعهدات سطح سرویس (SLA – Service Level Agreement) مثل پایداری (Uptime)، مقیاسپذیری (Scale)، پاسخدهی (Responsiveness)، و سایر ویژگیهای مهم معماری.
اما امروز، معماریهایی مثل microservices (ریزسرویسها – معماری مبتنی بر سرویسهای کوچک و مستقل) بهطور آزادانه از مفاهیمی استفاده میکنن که قبلاً فقط مختص حوزه عملیات بودن. مثلاً مقیاسپذیری پویا (Elastic Scale) در گذشته باید بهسختی در ساختار معماری پیادهسازی میشد (نگاه کنید به فصل ۱۵)، اما امروزه ریزسرویسها این موضوع رو سادهتر و با همکاری بین معماران و تیم DevOps (توسعه و عملیات یکپارچه) مدیریت میکنن.
تاریخچهی توسعهی نرمافزار، پر از درسهای آموزندهست — هم خوب، هم بد. ما معمولاً فرض میکنیم قابلیتهایی مثل elastic scale (مقیاسپذیری پویا) یه روزی ناگهان توسط یه توسعهدهنده باهوش اختراع شدن، اما واقعیت اینه که این ایدهها اغلب حاصل تجربههای سخت و شکستهای پرهزینه هستن.
Pets.com یکی از نمونههای اولیهی چنین تجربههایی بود. این شرکت در اوایل دوران اینترنت پا به عرصه گذاشت، با این امید که تبدیل به Amazon.com در حوزهی فروش لوازم حیوانات خانگی بشه. خوشبختانه، تیم بازاریابی بسیار خلاقی داشتن که یک شخصیت تبلیغاتی بامزه اختراع کرد: یک جورابعروسکی با میکروفن که حرفهای شوخطبعانه میزد. این شخصیت تبلیغاتی به سرعت محبوب شد و حتی در مراسم عمومی و مسابقات ملی ظاهر شد.
اما متأسفانه، مدیریت Pets.com به نظر میرسه که همهی بودجهشون رو صرف همین شخصیت تبلیغاتی کردن و چیزی برای زیرساخت باقی نذاشتن. وقتی سفارشها شروع به سرازیر شدن کرد، شرکت آمادگی لازم رو نداشت. وبسایت کند شد، تراکنشها گم میشدن، ارسالها با تأخیر انجام میشد، و خلاصه همهچیز به بدترین شکل ممکن پیش رفت. اوضاع اونقدر وخیم شد که شرکت مدت کوتاهی بعد از بحران کریسمس، تعطیل شد و تنها دارایی ارزشمند باقیمونده — همون شخصیت تبلیغاتی — رو به یک رقیب فروخت.
چیزی که این شرکت بهش نیاز داشت، elastic scale بود: توانایی اینکه در زمان نیاز، منابع بیشتری (مثل سرور یا پردازشگر) فعال کنن. امروز، ارائهدهندههای خدمات ابری (Cloud Providers) این قابلیت رو بهعنوان یک خدمت عادی در اختیار قرار میدن. اما در روزهای ابتدایی اینترنت، شرکتها مجبور بودن خودشون زیرساختشون رو مدیریت کنن، و خیلیها قربانی پدیدهای شدن که تا اون زمان کمتر شنیده شده بود: موفقیت بیشازحد هم میتونه یه کسبوکار رو نابود کنه.
تجربهی Pets.com و داستانهای مشابه دیگه، باعث شد مهندسها دست به کار بشن و فریمورکهایی توسعه بدن که معماران نرمافزار امروزه ازشون بهره میبرن.
در بخشهای بعدی، برخی از نقاط تلاقی جدید بین نقش معمار نرمافزار و سایر بخشهای سازمان بررسی میشن؛ نقاطی که توانمندیها و مسئولیتهای تازهای رو برای معماران به همراه دارن.
بهطور سنتی، معماری نرمافزار از فرآیند توسعهای که برای ساخت نرمافزار استفاده میشه، جدا بوده. دهها روش محبوب برای ساخت نرمافزار وجود دارن، از جمله مدل Waterfall (آبشاری) و انواع مختلف Agile (چابک) مثل Scrum، Extreme Programming (XP)، Lean و Crystal، که بیشترشون تأثیر مستقیمی بر معماری نرمافزار نمیذارن.
اما در سالهای اخیر، پیشرفتهای مهندسی باعث شدن دغدغههای مربوط به فرآیند هم وارد حوزه معماری بشن. در اینجا، مفیده که بین "فرآیند توسعه نرمافزار" و "رویههای مهندسی" تمایز قائل بشیم.
وقتی از process (فرآیند) صحبت میکنیم، منظورمون نحوه تشکیل و مدیریت تیمها، برگزاری جلسات، و سازماندهی جریان کاریه؛ یعنی بیشتر به جنبههای سازماندهی انسانها و تعاملاتشون مربوط میشه.
اما software engineering practices (رویههای مهندسی نرمافزار)، به روشهایی گفته میشه که مستقل از فرآیند خاصی هستن، اما مزایای تکرارپذیر و اثباتشدهای دارن. بهعنوان مثال، continuous integration (ادغام مداوم) یک رویهی مهندسی مؤثر و ثابتشدهست که وابسته به هیچ فرآیند خاصی نیست.
خاستگاه روش Extreme Programming (XP) بهخوبی تفاوت بین فرآیند (Process) و رویههای مهندسی (Engineering Practices) رو نشون میده. اوایل دهه ۹۰ میلادی، گروهی از توسعهدهندگان باتجربه به رهبری Kent Beck شروع به زیر سؤال بردن دهها فرآیند توسعه نرمافزار رایج اون زمان کردن. از نظر اونها، هیچکدوم از این روشها بهطور مداوم نتایج موفقیتآمیز تولید نمیکردن. یکی از بنیانگذاران XP گفته بود که انتخاب یکی از این فرآیندهای موجود "به اندازه شیر یا خط انداختن، برای موفقیت پروژه تضمین ایجاد میکنه!"
اونا تصمیم گرفتن بازنگری کنن که چطور باید نرمافزار ساخت و پروژهی XP رو در مارس ۱۹۹۶ شروع کردن. برای طراحی این روش، اونها دانش متداول رایج رو کنار گذاشتن و تمرکز رو روی اون دسته از رویههایی گذاشتن که در گذشته به موفقیت پروژه منجر شده بودن — البته در حد افراط. دلیلشون هم این بود که تو پروژههای قبلی، بین تعداد بیشتر تستها و کیفیت بالاتر، یک رابطه مستقیم دیده بودن. به همین خاطر، رویکرد XP در تستنویسی به شدت پیش رفت: توسعه باید test-first باشه، یعنی نوشتن تست قبل از کدنویسی، تا مطمئن بشن همه کدها قبل از ورود به مخزن کد (Code Base) تست شدهان.
XP در کنار سایر روشهای Agile قرار گرفت که دیدگاههای مشابهی داشتن، اما XP از معدود متدولوژیهایی بود که شامل رویههای مهندسی مشخصی بود؛ مثل automation (خودکارسازی)، testing (تستنویسی)، continuous integration (ادغام مداوم) و سایر تکنیکهای ملموس و مبتنی بر تجربه.
تلاشها برای پیشبرد بُعد مهندسی توسعه نرمافزار با انتشار کتاب Continuous Delivery (از انتشارات Addison-Wesley Professional) ادامه پیدا کرد — کتابی که نسخهای بهروز شده از بسیاری از رویههای XP محسوب میشه — و این مسیر در نهایت به جنبش DevOps منتهی شد. بهنوعی، انقلاب DevOps زمانی شکل گرفت که بخش عملیات (Operations) شروع کرد به پذیرش همون رویههای مهندسیای که در XP توصیه شده بود: مثل خودکارسازی، تست، منابع حقیقت واحد بهصورت اعلامی (Declarative Single Source of Truth) و غیره.
ما بهشدت از این پیشرفتها حمایت میکنیم؛ چون اینها همون گامهای تدریجیای هستن که در نهایت باعث میشن توسعه نرمافزار به یک رشتهی مهندسی واقعی و بالغ تبدیل بشه.
تمرکز بر رویههای مهندسی (Engineering Practices) اهمیت زیادی داره. اول اینکه توسعهی نرمافزار از بسیاری جهات، هنوز فاقد ویژگیهاییست که در رشتههای مهندسی بالغتر وجود داره. برای مثال، مهندسان عمران میتونن تغییرات سازهای رو با دقت بسیار بیشتری پیشبینی کنن نسبت به جنبههای ساختاری مشابه در نرمافزار.
دوم اینکه یکی از پاشنهآشیلهای توسعه نرمافزار، برآورد (Estimation) هست — اینکه چقدر زمان، چه میزان منابع، و چقدر هزینه نیازه. بخشی از این دشواری به دلیل روشهای حسابداری قدیمیست که با ماهیت اکتشافی توسعهی نرمافزار سازگار نیستن. اما بخشی دیگه از مشکل به این برمیگرده که بهطور سنتی، ما در برآورد ضعیف بودیم، حداقل تا حدی بهخاطر وجود unknown unknowns (چیزهایی که نمیدونیم که نمیدونیم).
«...چون همونطور که میدونیم، چیزهایی هستن که میدونیم میدونیم. و چیزهایی هم هستن که میدونیم نمیدونیم. اما همچنین چیزهایی هستن که نمیدونیم که نمیدونیمشون.»
— دونالد رامسفلد، وزیر دفاع پیشین آمریکا
Unknown unknowns دشمن بزرگ سیستمهای نرمافزاری هستن. بسیاری از پروژهها با فهرستی از known unknowns شروع میشن: مواردی که تیم توسعه میدونه باید دربارهی دامنهی مسأله یا تکنولوژی یاد بگیره. اما پروژهها اغلب قربانی unknown unknowns میشن: چیزهایی که هیچکس نمیدونست قراره پیش بیان ولی بهطور ناگهانی ظاهر میشن.
به همین دلیله که همهی پروژههای مبتنی بر Big Design Up Front (طراحی کامل از ابتدا) دچار مشکل میشن: چون معماران نمیتونن برای ناشناختههای ناشناخته طراحی کنن. به نقل از مارک، یکی از نویسندههای این کتاب:
«همهی معماریها در نهایت بهصورت تکرارشونده درمیآن، فقط Agile زودتر این موضوع رو به رسمیت میشناسه و اجراش میکنه.»
بنابراین، هرچند فرآیند توسعه معمولاً از معماری جدا در نظر گرفته میشه، اما یک فرآیند تکرارشونده (Iterative Process) بیشتر با ذات معماری نرمافزار همخوانی داره. تیمهایی که سعی میکنن یک سیستم مدرن مثل microservices بسازن ولی از فرآیندهای قدیمی مثل Waterfall استفاده کنن، با اصطکاک زیادی مواجه میشن؛ چون این فرآیندها واقعیتهای توسعه نرمافزار رو نادیده میگیرن.
اغلب، معمار پروژه همزمان رهبر فنی پروژه هم هست، و بنابراین رویههای مهندسی مورد استفادهی تیم رو هم تعیین میکنه. همانطور که معمار باید دامنهی مسئله رو پیش از انتخاب سبک معماری درک کنه، باید اطمینان حاصل کنه که سبک معماری و رویههای مهندسی بهصورت همافزا و مکمل (Symbiotic) با هم کار میکنن.
برای مثال، یک معماری مبتنی بر microservices فرض رو بر مواردی مثل تأمین خودکار ماشینها (automated provisioning)، تست خودکار، استقرار خودکار، و مجموعهای از مفروضات دیگه میذاره. اگر بخوای چنین معماریای رو با یک تیم عملیات قدیمی، فرآیندهای دستی، و تستنویسی محدود بسازی، با چالشهای بزرگی روبرو میشی.
همونطور که هر دامنهی مسئلهای سبک معماری خاص خودش رو میطلبه، رویههای مهندسی هم باید با معماری هماهنگ باشن.
سیر تحول تفکر از Extreme Programming به Continuous Delivery همچنان ادامه داره. پیشرفتهای اخیر در رویههای مهندسی، قابلیتهای تازهای رو در حوزه معماری ممکن ساختن. کتاب جدید نیل (Neal)، به نام Building Evolutionary Architectures (انتشارات O’Reilly)، راههای جدیدی رو برای اندیشیدن به تلاقی بین رویههای مهندسی و معماری معرفی میکنه؛ که این دیدگاه به خودکارسازی بهتر حاکمیت معماری (Architectural Governance) کمک میکنه.
اگرچه اینجا اون کتاب رو خلاصه نمیکنیم، اما باید بدونی که زبان مفهومی و شیوهی تفکر جدیدی رو معرفی میکنه که در ادامهی این کتاب، نقش مهمی خواهد داشت. کتاب نیل تکنیکهایی رو ارائه میده برای ساخت معماریهایی که بهمرور زمان بهصورت انعطافپذیر تغییر میکنن. ما در فصل ۴، معماری رو ترکیبی از الزامات (Requirements) و نگرانیهای مکمل (Additional Concerns) توصیف میکنیم — همونطور که در شکل 1-7 نشون داده شده.

همونطور که هر کسی که تجربهای در دنیای توسعه نرمافزار داره میدونه، هیچچیز در این حوزه ثابت نمیمونه. بنابراین، ممکنه معماران یک سیستم رو طوری طراحی کنن که معیارهای خاصی رو برآورده کنه، اما اون طراحی باید از دو مرحلهی چالشبرانگیز عبور کنه:
۱. پیادهسازی — چطور میشه مطمئن شد که طراحی مورد نظر معمار بهدرستی پیادهسازی شده؟
۲. تغییرات اجتنابناپذیر — تغییراتی که بهطور طبیعی و دائمی از دل اکوسیستم توسعه نرمافزار به وجود میان.
چیزی که واقعاً بهش نیاز داریم، یک معماری تکاملی (evolutionary architecture) هست.
کتاب Building Evolutionary Architectures مفهوم استفاده از fitness functions (توابع سنجش تناسب) رو معرفی میکنه؛ ابزاری برای محافظت و نظارت بر ویژگیهای معماری در طول زمان، وقتی که تغییرات اجتنابناپذیر رخ میدن.
این مفهوم از حوزهی evolutionary computing (محاسبات تکاملی) گرفته شده. زمانی که یک الگوریتم ژنتیکی طراحی میشه، توسعهدهندگان از تکنیکهای مختلفی برای ایجاد تغییر (mutation) در راهحلها استفاده میکنن تا بهصورت تکرارشونده به راهحلهای جدید و بهتر دست پیدا کنن. اما برای اینکه بفهمن راهحل جدید به هدف نزدیکتر شده یا نه، باید اون رو بسنجن؛ این سنجش توسط fitness function انجام میشه.
مثلاً اگر قراره یک الگوریتم ژنتیکی برای حل مسئلهی travelling salesperson problem طراحی بشه (هدف این مسئله پیدا کردن کوتاهترین مسیر بین چندین شهره)، تابع تناسب یا fitness function طول مسیر رو اندازه میگیره تا ببینه آیا جواب بهتر شده یا نه.
کتاب Building Evolutionary Architectures از همین ایده استفاده میکنه تا چیزی به اسم architectural fitness functions بسازه — یعنی ارزیابی عینی از سلامت یا تمامیت (integrity) برخی از ویژگیهای معماری.
این ارزیابی میتونه از روشهای مختلفی استفاده کنه، مثل معیارها (metrics)، تستهای واحد (unit tests)، پایش (monitoring) و حتی chaos engineering (مهندسی آشوب – روشی برای تست پایداری سیستم از طریق ایجاد اختلال عمدی).
برای مثال، فرض کن یه معمار، «زمان بارگذاری صفحات» رو بهعنوان یک ویژگی حیاتی معماری شناسایی کرده باشه. حالا برای اینکه بشه سیستم رو در طول زمان تغییر داد بدون اینکه عملکرد افت کنه، معمار یک fitness function طراحی میکنه که بهصورت تست، زمان بارگذاری هر صفحه رو اندازه میگیره و این تست رو به بخشی از فرآیند continuous integration (ادغام مداوم) پروژه اضافه میکنه. به این شکل، معمار همیشه از وضعیت بخشهای حساس معماری باخبره، چون برای هر بخش، یک مکانیزم بررسی مشخص در قالب fitness function داره.
در این کتاب به جزئیات کامل این توابع نمیپردازیم، اما در جاهایی که مناسب باشه، به فرصتها و نمونههای استفاده از این رویکرد اشاره میکنیم. نکتهی مهم اینه که هرچه fitness functionها بیشتر و مداومتر اجرا بشن، بازخورد دقیقتری هم ارائه میدن. این دقیقاً نشون میده که اتخاذ رویههای مهندسی چابک مثل continuous integration، automated provisioning (تأمین خودکار ماشینها)، و روشهای مشابه، ساخت معماریهای مقاومتر رو سادهتر میکنه.
همچنین، این مسئله پیوند عمیق و روزافزون بین معماری و رویههای مهندسی رو بهخوبی نشون میده.
واضحترین نقطهی تلاقی اخیر بین معماری و حوزههای مرتبط، با ظهور DevOps اتفاق افتاد — که نتیجهی بازنگری در برخی اصول بنیادین معماری بود.
برای سالها، بسیاری از شرکتها عملیات (Operations) رو یک بخش جدا از توسعه نرمافزار میدونستن؛ معمولاً هم این بخش رو برای صرفهجویی در هزینه به شرکتهای ثالث برونسپاری میکردن. بسیاری از معماریهایی که در دهههای ۱۹۹۰ و ۲۰۰۰ طراحی شدن، بر این فرض استوار بودن که معماران کنترلی روی عملیات ندارن، و بنابراین بهشکل تدافعی (Defensively) با این محدودیت طراحی شده بودن (برای نمونهی خوب این نوع طراحی، به معماری مبتنی بر فضا یا Space-Based Architecture در فصل ۱۵ مراجعه کن).
اما چند سال پیش، برخی شرکتها شروع کردن به آزمایش معماریهایی که بسیاری از دغدغههای عملیاتی رو با خود معماری ترکیب میکردن. مثلاً در معماریهای قدیمیتر، مثل معماری مبتنی بر ESB-driven SOA (معماری سرویسگرای مبتنی بر Enterprise Service Bus)، وظیفههایی مثل مقیاسپذیری پویا (elastic scale) بر دوش معماری گذاشته شده بود — که همین موضوع معماری رو بهشدت پیچیدهتر میکرد.
در اصل، معماران مجبور بودن طراحیشون رو بهگونهای انجام بدن که ضعف ناشی از برونسپاری عملیات رو جبران کنه. بنابراین، معماریهایی میساختن که بهتنهایی باید مقیاسپذیری، کارایی (performance)، کشسانی (elasticity)، و بسیاری ویژگیهای دیگه رو مدیریت میکرد. نتیجهی این سبک طراحی، پیچیدگی بسیار بالای معماری بود.
اما طراحان سبک معماری microservices (ریزسرویسها) متوجه شدن که این مسائل عملیاتی، بهتره توسط تیم عملیات مدیریت بشه. با ایجاد یک همکاری مؤثر بین معماری و عملیات، معماران میتونن طراحی سیستم رو سادهتر کنن و مسئولیت مواردی که عملیات بهتر از عهدهش برمیاد رو به اون واگذار کنن.
در واقع، درک این موضوع که استفادهی اشتباه از منابع باعث پیچیدگیهای ناخواسته شده، باعث شد که معماران و تیم عملیات با همکاری هم معماری ریزسرویسها رو شکل بدن — که جزئیات اون رو در فصل ۱۷ بررسی میکنیم.
یکی از باورهای رایج (axiom) در معماری نرمافزار این بوده که معماری نرمافزار تقریباً مستقل از فرآیند توسعهی نرمافزاره — یعنی اینکه چطور نرمافزار ساخته میشه (process)، تأثیر چندانی روی ساختار معماری نداره. بنابراین، اگرچه فرآیند توسعه تا حدی روی معماری نرمافزار تأثیر میذاره (بهویژه در زمینهی engineering practices)، ولی از لحاظ تاریخی، این دو بهعنوان حوزههایی جداگانه در نظر گرفته میشدن.
اغلب کتابهای معماری نرمافزار هم فرآیند توسعه رو نادیده میگیرن و فرضیات اشتباهی دربارهی قابل پیشبینی بودن فرآیندها مطرح میکنن. با این حال، فرآیندی که تیمها با استفاده از اون نرمافزار توسعه میدن، تأثیرات زیادی بر ابعاد مختلف معماری نرمافزار داره.
برای مثال، در چند دههی گذشته، بسیاری از شرکتها روشهای توسعهی Agile رو اتخاذ کردن، چون با ذات پویای توسعهی نرمافزار همخوانی داره. معمارانی که در پروژههای Agile فعالیت میکنن، میتونن روی تکرارشونده بودن توسعه حساب باز کنن و در نتیجه، بازخورد سریعتر برای تصمیمگیریها داشته باشن. این بازخورد سریع به معماران این امکان رو میده که با جسارت بیشتری دست به آزمایش، نوآوری، و تصمیمگیریهایی بزنن که به اطلاعات برگشتی وابستهست.
همونطور که نقلقول قبلی از مارک میگه: «همهی معماریها در نهایت تکرارشونده میشن؛ فقط زمانش متفاوته.»
بر همین اساس، در این کتاب فرض پایهمون استفاده از متدولوژیهای Agile خواهد بود، مگر اینکه خلافش رو مشخص کنیم. برای مثال، هنوز هم رایجه که معماریهای یکپارچه (monolithic architectures) قدیمی به خاطر سن سیستم، سیاستهای سازمانی، یا عوامل غیر فنی دیگه، با فرآیندهای توسعهی قدیمی اجرا بشن.
یکی از زمینههایی که متدولوژیهای Agile در اون درخشان ظاهر میشن، بازساخت (restructuring) معماریه. تیمها اغلب در میانهی راه متوجه میشن که باید معماریشون رو از یک الگو به الگوی دیگه منتقل کنن. مثلاً ممکنه تیمی با معماری یکپارچه (Monolith) شروع کرده باشه چون در ابتدا سریع و ساده بوده، اما حالا نیاز دارن اون رو به یک معماری مدرنتر مهاجرت بدن.
روشهای Agile از این نوع تغییرات بهخوبی پشتیبانی میکنن، چون حلقهی بازخورد تنگاتنگی دارن و تکنیکهایی مثل Strangler Pattern (الگوی خفهکننده – برای تدریجی جایگزین کردن سیستم قدیمی با جدید) و feature toggles (سوئیچ کردن ویژگیها) رو تشویق میکنن.
بخش بزرگی از توسعهی جدی اپلیکیشنها، شامل استفاده از ذخیرهسازی خارجی داده میشه — که اغلب بهشکل پایگاه داده رابطهای (Relational Database) یا (بهطور فزاینده) پایگاههای دادهی NoSQL هست. با این حال، بسیاری از کتابهای معماری نرمافزار این جنبهی مهم از معماری رو خیلی سطحی بررسی میکنن.
بین کد و داده یک رابطهی همزیستی (Symbiotic) وجود داره: هیچکدوم بدون دیگری کاربردی ندارن.
مدیران پایگاه داده (DBA – Database Administrator) معمولاً کنار معماران کار میکنن تا معماری داده برای سیستمهای پیچیده رو طراحی کنن — بررسی میکنن که روابط بین دادهها و استفادهی مجدد از اونها چه اثری روی مجموعهای از اپلیکیشنها داره. البته ما در این کتاب وارد جزئیات تخصصی این حوزه نخواهیم شد.
با این حال، وابستگی به ذخیرهسازی خارجی رو هم نادیده نمیگیریم. بهویژه زمانی که دربارهی جنبههای عملیاتی معماری و مفهوم معماری کوانتومی (Architectural Quantum) صحبت میکنیم (نگاه کنید به بخش “Architectural Quanta and Granularity” در صفحه ۹۲)، مسائل مهم خارجی مثل پایگاه دادهها رو هم لحاظ میکنیم.
اگرچه دامنهی معماری نرمافزار بسیار گسترده و تقریباً بیانتهاست، اما عناصر وحدتبخشی هم در اون وجود دارن. نویسندگان این کتاب از طریق تجربه و مواجهه مکرر با یک اصل مهم، قبل از هر چیز، به «قانون اول معماری نرمافزار» پی بردهان:
همه چیز در معماری نرمافزار یک بدهبستان (trade-off) است.
— قانون اول معماری نرمافزار
در معماری نرمافزار، هیچ چیز در یک طیف صاف و ساده قرار نمیگیره. هر تصمیمی باید با در نظر گرفتن عوامل متضاد و متعدد گرفته بشه.
اگر یک معمار فکر میکنه چیزی رو کشف کرده که trade-off نداره، احتمالاً فقط هنوز trade-off اون رو پیدا نکرده!
— نتیجهگیری اول (Corollary 1)
ما معماری نرمافزار رو فراتر از اسکلتبندی ساختاری تعریف میکنیم — و شامل اصول (principles)، ویژگیها (characteristics) و موارد دیگه هم میدونیم. به همین دلیل، معماری فقط ترکیبی از عناصر ساختاری نیست، بلکه نگاه عمیقتری رو میطلبه. این نگرش در «قانون دوم معماری نرمافزار» بازتاب پیدا میکنه:
"چرا" مهمتر از "چگونه" است.
— قانون دوم معماری نرمافزار
نویسندگان کتاب به اهمیت این دیدگاه زمانی پی بردن که در کارگاههای آموزشی، تمرینات طراحی معماری توسط دانشجویان رو بررسی میکردن. از اونجایی که این تمرینها زمانبندیشده بودن، تنها چیزی که باقی میموند، نمودارهایی بود که توپولوژی معماری رو نشون میدادن. یعنی فقط مستندات مربوط به چگونهی حل مسئله ثبت میشد، اما چرایی تصمیمات تیم مشخص نبود.
یک معمار میتونه به یک سیستم موجود که هیچ پیشزمینهای ازش نداره نگاه کنه و متوجه بشه ساختار معماری اون چطوری کار میکنه، اما خیلی سخت میتونه توضیح بده چرا انتخابهایی خاص در طراحی اون سیستم انجام شده.
در طول این کتاب، ما روی این موضوع تمرکز داریم که چرا معماران تصمیماتی خاص میگیرن و trade-offهای مرتبط با اون تصمیمات چی هستن. همچنین، تکنیکهای مناسبی رو برای مستندسازی این تصمیمات مهم معرفی میکنیم، از جمله Architecture Decision Records (رکوردهای تصمیم معماری) که در صفحه ۲۸۵ توضیح داده شدهاند.