نکات کلیدی
-
قبل از اینکه درباره چگونگی پیادهسازی یک رابط فکر کنید، بخشهای رابط را ترسیم کنید و برای آنها مالک تعیین کنید.
-
بفهمید آیا رابط شامل یک انسان است یا باید کاملاً خودکار باشد. مشارکت انسانی معمولاً تنها دلیل استفاده از یک رابط همگام است.
-
مالکیت و حضور یک انسان (یا نبود آن) محرکهای کلیدیِ نیازمندیهای غیرعملکردیِ هر رابط هستند. به نوبه خود، این موضوع انتخابهای فناوری/مصالحهها را که طراحان رابط و توسعهدهندگان باید در نظر بگیرند هدایت میکند.
-
این فرایند فکری باید برای هر رابط بهصورت جداگانه دنبال شود. شما نمیتوانید دو رابط را بدون موشکافی کردن، در یک دسته قرار دهید.
طراحی خوبِ رابط یک چالش مهندسی پیچیده با ابعاد فراوان است. در این مقاله، من ابعاد کلیدیِ مالکیت و اینکه آیا یک انسان درگیر است یا نه را بررسی میکنم.
مقدمه
در آگوست ۲۰۱۷، مقالهای از معمار ارشد سازمانی Temenos، John Schlesinger، مورد توجه قرار گرفت که بیش از یک دهه پیش نوشته شده بود و به موضوع یکپارچهسازی برنامهها میپرداخت. با وجود تجربه محدود در حوزه یکپارچهسازی در آن زمان، درک کامل مطالب مطرحشده در مقاله دشوار بود. برجستهترین مفهومی که در این مقاله به چشم میخورد، «سناریوی ممنوعه» بود که با نمودار سادهای (شکل ۱) توضیح داده شده است.
در این مقاله استدلال شده که چنین رویکردی به اتصال تنگاتنگ بین دو مدیر منبع منجر میشود و در عمل، مدیر منبع مبدأ را به نوعی «گروگان» مدیر منبع مقصد تبدیل میکند. از منظر مهندسی، ویژگیهای غیرعملکردی سیستم مبدأ بهطور مستقیم به ویژگیهای غیرعملکردی سیستم مقصد وابسته میشود. بهعنوان مثال، اگر مدیر منبع مقصد ۲ ثانیه زمان برای پاسخگویی نیاز داشته باشد، این ۲ ثانیه به تأخیر هر عملیات ارائهشده توسط مدیر منبع مبدأ اضافه خواهد شد.

شکل ۱: سناریوی ممنوعهِ یکپارچهسازی برنامهها (Application Integration)
سؤالهای زیادی پیش آمد: پس تکلیف همه این خدمات وب (SOAP و REST) که سالها در معرضشان بودهام چه میشود؟ اگر لازم باشد دو برنامه تکههایی از اطلاعات را دوطرفه با هم مبادله کنند و این کار را خیلی سریع انجام دهند چه؟ چرا این سناریو ممنوع است؟ آیا یکسری مشکل پنهانِ پیادهسازی ایجاد میکند؟ و خیلی موارد دیگر. بقیه مقاله به برخی از سؤالها پاسخ داد.
در طول سالها، فرصت داشتم این مفهوم را با John و همکاران دیگر با جزئیات بحث کنم، تلاش کردم ایدهها را با بسیاری از معماران بانکی مطرح کنم، و همچنین دوستان و افراد دیگری را در رویدادهای تصادفیِ توسعهدهندگان ملاقات کردم.
چندین سال طول کشید تا ذهنم را از این مفاهیم پاک کنم و آنها را به یک انتزاع تبدیل کنم که وقتی درباره رابطها صحبت میکنم، فکر کردنم را هدایت کند. امروز این سردرگمی را همهجا میبینم، حتی در افرادی که در نهادهای بزرگ، مقامهای بسیار ارشد دارند. هدف این مقاله این است که یک چارچوب ساده برای طبقهبندیِ رابطها و فهمیدن برخی مفاهیم مهم قبل از پیادهسازی آنها برقرار کند.
دو بُعد کلیدی که نوع رابط را تعریف میکنند
در رایانش، یک رابط یک مرز مشترک است که در آن، دو یا چند مؤلفه از یک سیستم رایانهای اطلاعات را مبادله میکنند. این مبادله میتواند بین نرمافزار، سختافزار رایانه، دستگاههای جانبی، انسانها، و ترکیبهایی از اینها باشد.
با تمرکز روی نرمافزار، مهندسان معمولاً رابطها را بر اساس ابعاد متفاوت گروهبندی/طبقهبندی میکنند. میتواند بر اساس دامنه، سیستم، همگام یا ناهمگام، پروتکل، الگوی یکپارچهسازی، و غیره گروهبندی شود. همه این ابعاد برای پیادهسازی یک رابط ضروری هستند. اما آنها در وهله اول به شما نمیگویند چگونه این انتخابها را انجام دهید. چه زمانی باید تصمیم بگیرید HTTP یا gRPC را استفاده کنید؟ آیا میتوانم برای یک مورد کاربرد مشخص از Kafka یا MQ استفاده کنم؟ آیا تفاوتهایی وجود دارد که اگر یک انتخاب خاص انجام بدهم باید بدانم؟
من دو بُعد کلیدی را معرفی میکنم که به نظر من، در انجام انتخابهای آگاهانه هنگام فکر کردن درباره یک رابط مشخص خیلی کمک میکنند:
الف) اینکه آیا یک انسان در رابط دخیل است یا نه، و
ب) مالکیت سیستمهایی که در رابط دخیل هستند.
با گرفتن دو بُعدی که در این بخش بحث شد، میتوانیم همه رابطها را به چهار دسته طبقهبندی کنیم، که در شکل ۲ نشان داده شدهاند.

شکل ۲: انواع رابطها (Types of Interfaces)
اصطلاحات ارتباط بینفرایندی و یکپارچهسازی برنامهها بهطور گسترده در صنعت استفاده میشوند. من اصطلاح «تعامل» را از John و از مشارکتم در معماری Temenos طی چند سال گذشته یاد گرفتم. فرصت داشتم عمیقاً وارد مفاهیم و تفاوتِ برخورد با آنها بهعنوان یک مفهوم جداگانه شوم. ChatGPT بعد از اینکه توضیح دادم دنبال چه چیزی هستم، اصطلاح «ارکستراسیون تجربه» را به من داد. این مفهوم امروز در سازمانهایی که از معماریهای توزیعشده استفاده میکنند و یک لایه تجربه کاربری مشترک دارند که به چندین برنامه ناهمگون (اغلب بدون سر/هدلس (headless)) پشت پرده دست میزند، بسیار رایج است.
فهمیدن اینکه با کدام نوع از رابطها سروکار دارید، یک گام اول ضروری برای فهمیدن این است که چطور آنها را بهطور مؤثر پیادهسازی کنید. فهمیدن نیروهای اثرگذار برای هر نوع رابط به فهمیدن مصالحهها کمک میکند.
ارتباط بینفرایندی
ارتباط بینفرایندی (IPC) یک مفهوم قدیمی است. بسیاری از برنامههای پیچیده به مؤلفهها (فرایندها) شکسته میشوند، و این مؤلفهها داده را از طریق APIهای برنامهنویسیشده (programmatic APIs) مبادله میکنند. در یک برنامه تکپارچه، این کار اغلب با استفاده از تراکنشها و یک پایگاهداده واحد انجام میشود.
IPC در برنامههای توزیعشدهای که بر پایه میکروسرویسها ساخته شدهاند کمی پیچیدهتر است. وقتی چندین مؤلفه دارید با شاید پایگاهدادههای متفاوت، به یک رویکرد متفاوت نیاز دارید. مؤلفهها میتوانند به روشهای زیادی ارتباط برقرار کنند، مثلاً از طریق پایگاهداده (که معمولاً واقعاً بد است)، فراخوانیهای همگام، یا سازوکارهای ناهمگام (پیامها یا فایلها).
در IPC، معمولاً یک مالک واحد برای کل معماری برنامه وجود دارد (یک توسعهدهنده ارشد یا معمار ارشد). این مالک میتواند با تیمهایی که مؤلفههای متفاوت را میسازند کار کند و همکاری را تسهیل کند، اغلب حول استانداردها و پروتکلهای مشترک. زندگی خیلی آسانتر است وقتی لوکسِ داشتن استانداردها و پروتکلهای مشترک را دارید. اگر یک چالش داشته باشید، تیم میتواند بهطور جمعی یک راهحل پیدا کند یا به یک استاندارد یا پروتکل دیگر با قابلیتهای متفاوت تغییر مسیر دهد.
من وارد جزئیات همه گزینههای ممکن برای IPC نمیشوم، چون معمولاً در هر کتابی درباره معماری برنامه یا یکپارچهسازی یک فصل درباره این موضوع وجود دارد. فناوریهایی مثل اشتراکگذاری پایگاهداده، RPC، APIهای REST/SOAP، انواع مختلف صفهای پیام، و فناوریهای Pub/Sub همگی گزینههای ممکن برای IPC هستند.
نظر من (معماری سراسر نظرهاست) این است که IPC بین دو مؤلفه که انسان در آن دخیل نیست باید با یک فناوری ناهمگام انجام شود که از یک کارگزار برای ماندگارکردن پیامها استفاده میکند. این تنها راه رسیدن به ویژگی ضروریِ اتصالِ سست (loose coupling) است، که بهطور چشمگیر دسترسپذیری و مقیاسپذیری برنامه را افزایش میدهد. این همچنین پاسخ به نکته «سناریوی ممنوعه» است که در مقدمه مطرح شد. سناریوی ممنوعه سه مشکل اصلی دارد:
الف) مشکلات مدیریت تراکنش،
ب) مشکلات تأخیر، و
ج) مشکلات قابلیت اعتماد.
اگر برنامه از صفر طراحی شده باشد، احتمالاً مؤلفههای همگن خواهد داشت. اگر این درست باشد، IPC حتی آسانتر است. مؤلفهها میتوانند طوری طراحی شوند که پیامهای مؤلفههای دیگر را بفهمند و فوراً آنها را به یک فرمان تبدیل کنند.
یکپارچهسازی برنامهها
سیستم به سیستم؛ مالکان متعدد
وقتی یک رابط باید بین دو برنامه با مالکان متفاوت ساخته شود، بدون هیچ مشارکت انسانی، ما سناریوی یکپارچهسازی برنامهها را داریم. یکپارچهسازی برنامهها از برخی جهات شبیه IPC است؛ برای مثال، انتخاب ناهمگامِ مبتنی بر کارگزار که من برای IPC انجام میدهم، برای یکپارچهسازی برنامهها هم کمابیش به همان دلایل انجام میدهم. با این حال، در اینجا یک دلیل دیگر هم برای پرهیز از فناوریهای همگام وجود دارد: مالکیت و جداسازی مسئولیتها.
وقتی باید برنامهتان را با یک برنامه دیگر یکپارچه کنید، دو واقعیت اصلی وجود دارد که باید در نظر بگیرید:
الف) دانش شما از برنامه دیگر و اینکه چگونه کار میکند معمولاً کم است یا حتی وجود ندارد، و
ب) کنترل شما روی اینکه برنامه دیگر چگونه رفتار میکند نیز دوباره کم است یا وجود ندارد.
مقاومترین رویکرد برای یکپارچهسازی برنامهها (باز هم، یک نظر شخصی!) رویکردی است که در شکل ۳ نشان داده شده است.
هر یک از دو برنامهای که باید یکپارچه شوند یک رابط عمومی ارائه میدهد. رابط عمومی باید یک قرارداد باشد. این قرارداد میتواند یک توافق B2B بین دو مالک برنامه باشد. با این حال، هر برنامه همچنین میتواند رابط خارجیِ خودش را تعریف و منتشر کند و به سازگاری عقبرو/پیشرو، نسخهبندی، و غیره متعهد شود. هر رویکردی که باشد، قرارداد نباید تغییر کند، فارغ از اینکه چه تغییرهایی به برنامه وارد میشود. هر قرارداد باید شامل یک جریان (flow) باشد که اجازه میدهد برنامه یک رویداد محلی (که به مدل داده برنامه پایبند است) را به یک رویداد کسبوکاری (که از یک مدل داده پیروی میکند که کل سازمان میتواند بفهمد، از اینرو «کسبوکاری») تبدیل کند.

شکل ۳: یکپارچهسازی از طریق قراردادها (Integration via Contracts)
رابط میتواند بعد از اینکه دو قرارداد توافق شدند ساخته شود. ممکن است یک یا دو آداپتور لازم باشد، و یک مؤلفه که همکاری بین آداپتورها را تسهیل میکند، با استفاده از کارگزار در صورت نیاز. هنگام طراحی رابط، حیاتی است که این مؤلفهها تعریف شوند و برای آنها مالک تعیین شود. معمولاً به این مالکان باید به شکلی پول پرداخت شود تا رابط را بسازند و نگهداری کنند. یکی از دو مالک برنامه ممکن است موافقت کند مالک رابط باشد، یا یک طرف سوم میتواند مالک رابط باشد. بخشهایی از رابط هم ممکن است توسط طرفهای متفاوت مالکیت شوند (مثلاً هر مالک برنامه میتواند مالک آداپتور خودش باشد، و یک طرف سوم میتواند مالک منطق همکاری و کارگزار باشد).
نقش کارگزار در اینجا حیاتی است. حضور کارگزار، همراه با مالکیتِ بهروشنی تعریفشده، عیبیابی خطاها را بدیهی میکند. برای مثال، وقتی یک پیام گم میشود، میتوانید بررسی را از کارگزار شروع کنید. اگر پیام آنجا باشد، تولیدکننده فوراً بیگناه اعلام میشود. با دنبال کردن این خط فکری، شناسایی منشأ هر مسئله و انجام اقدام لازم کاملاً آسان است. همچنین مالک اقدام اصلاحی را هم شناسایی خواهید کرد بدون اینکه در زمانهای بحران نیاز به مذاکره داشته باشید.
گاهی یکی از دو برنامه ممکن است نخواهد «بازی کند». دو سناریوی رایج وجود دارد که این اتفاق در آنها رخ میدهد:
الف) مالک برنامه آنقدر بزرگ است که وارد مذاکره قرارداد نمیشود. در این حالت، مالک برنامه قرارداد عمومی خودش را ارائه میدهد و هر کسی که میخواهد یکپارچه کند باید مسیر خودش را پیدا کند. گاهی مالک برنامه آنقدر بزرگ است که ممکن است یکطرفه تصمیم بگیرد قرارداد را تغییر دهد، معمولاً با دادن یک اطلاعرسانی از قبل. مالک رابط باید بتواند این تغییرها را جا بدهد.
ب) مالک برنامه دیگر در دسترس نیست. این یک سناریوی رایج با برنامههای قدیمی یا رهاشده است. برای مثال، ممکن است مجبور باشید با یک برنامه legacy که یک رابط TCP با قالب اختصاصی ارائه میدهد یکپارچه شوید. باز هم، این به مالک رابط برمیگردد که این آشفتگی را جمعوجور کند. نکته خوب در اینجا این است که مالک برنامه معمولاً «زنده نمیشود» که تغییرهای تصادفی انجام دهد، پس پیچیدگی فقط یکبار باید مدیریت شود.
تعامل (Interaction)
انسان به سیستم؛ مالک واحد
حالا من توجه را به رابط کاربری منتقل میکنم. وقتی یک رابط کاربری باید در محدوده یک برنامه واحد ساخته شود (یعنی برنامه و رابط کاربری مالک مشترک دارند)، باز هم راحتیِ انتخاب استانداردها و پروتکلها وجود دارد، و همچنین یک محیط همکاری که مدیریت تغییر را تسهیل میکند.
آنچه این الگوی تعامل را بسیار متفاوت از ارتباط ماشین با ماشین میکند، حضور یک انسان است که برخی تواناییها (مثلاً استفاده از مغز برای فهمیدن یک خطای ناشناخته و درخواست کمک) و برخی نیازمندیها دارد.
انسان/کاربر میخواهد رابط کاربری وقتی نیاز دارد در دسترس باشد. برای مثال، یک برنامه اینترنتی باید در حالت ایدهآل بهصورت پیوسته (بدون downtime) در دسترس باشد. اگر یک رابط کاربری قرار است در زمان حضور در دفتر استفاده شود، پس کافی است سیستم در ساعات کاری در دسترس باشد. گذار تدریجی به کار از خانه و ساعات کاری انعطافپذیر برای برخی شغلها ممکن است نیازمندیهای دسترسپذیری برخی رابطهای کاربری را تغییر دهد.
بعد، انسان/کاربر میخواهد با سیستم بهصورت راحت تعامل کند. ما این را «کاربردپذیری» مینامیم؛ پژوهش و تخصص زیادی درباره ساخت رابط کاربری کاربردپذیر وجود دارد. یک بخش حیاتیِ کاربردپذیری، که برای رابطهای مدرن ضروری است، «پاسخگویی» است. وقتی حدود ۲۵ سال پیش شروع به استفاده از کامپیوتر کردم، طبیعی بود کاری انجام دهید و چند ثانیه صبر کنید تا سیستم درخواستتان را پردازش کند، حتی دقیقهها. امروز، اگر یک دکمه را کلیک کنم و صفحه بیشتر از ۳ ثانیه برای پاسخ طول بکشد، پر از اضطراب میشوم. بعد از ۵ ثانیه، این تبدیل به خشم میشود. انسان/کاربر بازخورد را هرچه سریعتر میخواهد. ارتباط باید «حس» همگام بودن داشته باشد (حتی اگر پیادهسازیِ زیرین همگام نباشد). تعریف دقیق اینکه چه سطحی از تأخیر قابل قبول است سخت است. بیش از یک دهه پیش، Amazon فهمید که هر ۱۰۰ میلیثانیه تأخیر رابط کاربری برایشان ۱٪ از فروش هزینه دارد.
ویژگی دیگرِ تعامل این است که انسان/کاربر تراکنش را مدیریت میکند (که در یکپارچهسازی برنامهها توسط قرارداد مدیریت میشود). بنابراین، بازخورد باید بهموقع و آسان برای اقدام کردن باشد. فرض کنید از یک رابط کاربری یک اقدام ساده و مستقیم را تحریک میکنیم که فقط به یک مؤلفه از برنامه زیرین دست میزند و در چند صد میلیثانیه تمام میشود. در آن صورت، انتظار داریم رابط کاربری به ما اطلاع دهد وقتی اقدام کامل شد. اگر یک گردشکار طولانیمدت را تحریک میکنیم، باید مطلع شویم، مثلاً گام بعدی چیست، کی کامل میشود، و چطور به ما اطلاع داده خواهد شد. اگر خطایی رخ دهد و درمان/اصلاح لازم باشد، انسان/کاربر باید گفته شود چگونه فرایند درمان را تحریک کند.
در مورد نظرها، بهترین راه برای پیادهسازی رابط کاربری از طریق یک پروتکل همگامِ مبتنی بر HTTP است. یک استدلال سرراست برای پشتیبانی از این نظر وجود دارد: اینترنت. سازوکارهای دیگر مثل gRPC یا servletهای ساده هم راههای خوبی برای پیادهسازی تعامل هستند.
ارکستراسیون تجربه
انسان به سیستم؛ مالکان متعدد
بسیاری از مهندسان/سازمانها ارکستراسیون تجربه را همانطور پیادهسازی میکنند که تعامل را پیادهسازی میکنند. با این حال، ریزهکاریهای مالکیت یعنی ایدههای بهتری از این وجود دارد.
اگر ارکستراسیون تجربه را با یک فراخوانی مستقیم API به یک سیستم دیگر که مالک آن نیستید پیادهسازی کنید، شما فوراً گروگان آن سیستم میشوید. دسترسپذیری شما اکنون وابسته به دسترسپذیری سیستم طرف سوم است. همین موضوع درباره تأخیر هم صدق میکند. پیامهای خطای شما و اقدامهای بعدی ممکن است وابسته به این باشند که چه اطلاعاتی از سیستم طرف سوم دریافت میکنید.
به نظر من، بهترین رویکرد برای پیادهسازی یک رابط ارکستراسیون تجربه استفاده از رویکردی است که در شکل ۴ آمده است.

شکل ۴: پیادهسازی ارکستراسیون تجربه
در اصل، شما باید یک برنامه خود-محتوا پیرامون رابط تجربه بسازید و از این برنامه برای کنترل/تحمیل نیازمندیهای تعامل که در بخش قبل توضیح دادم استفاده کنید.
برای کنترل آنچه به کاربر نشان میدهید، برنامه خود-محتوای شما باید API خودش را بسازد. شما همچنین به یک لایه ماندگاری نیاز دارید تا دادههای لازم را همگام کند و وضعیت خودتان را ذخیره کند. این دو بخش برنامه برای کنترل دسترسپذیری و تأخیر ضروری هستند؛ آنها همچنین اجازه میدهند پیامهای خطای خودتان، اقدامهای پیشنهادی، و عناصر دیگرِ تجربه کاربریتان را مدیریت کنید.
اگر تجربه شما به اندازه کافی پیچیده باشد، به یک لایه منطق کسبوکار نیاز خواهید داشت تا رفتار مطلوب را کدنویسی کند و یک موتور گردشکار برای مدیریت فرایندهای طولانیمدت. در حالی که این دو مؤلفه ممکن است به اندازه API و ماندگاری مهم نباشند، آنها باید در برنامههای در سطح سازمانی وجود داشته باشند. گردشکار میتواند رابط کاربری خودش را برای مدیریت کارها پیادهسازی کند. یک رویکرد تمیزتر (اما پیچیدهتر) از رویدادهای موتور گردشکار استفاده میکند تا کارهای گردشکار را با دیگر رابطهای کاربری موجود یکپارچه کند.
وقتی این رویکرد را دنبال میکنید، شما اطلاعات را با برنامههای دیگر بر اساس اصول سیستم-به-سیستم که قبلاً توصیف شد مبادله میکنید. داخل برنامه خود-محتوای خودتان، میتوانید هر فناوریای را که برای ارتباط بینفرایندیتان ترجیح میدهید استفاده کنید.
جمعبندی
یک بخش مهم از معماری این است که دیدگاههای متفاوت را روی هم بیندازیم و واقعیت را از منظرهای گوناگون بررسی کنیم. اعمال مفاهیمی که در این مقاله توصیف شد روی یک نمودار معماری عمومیِ نسبتاً استاندارد، دیدی را که در شکل ۵ نشان داده شده نتیجه میدهد. هر سازمان متوسط تا بزرگ احتمالاً هر چهار نوع رابطی را که توصیف کردم در نقاط مختلف پیادهسازی کرده است.

