زمانی که متخصصان در حال کار بر روی یک مشکل خاص هستند، به ندرت تلاش میکنند تا راهحلی کاملاً جدید و متفاوت از راهحلهای قبلی پیدا کنند. در عوض، آنها اغلب به تجربیات گذشته خود رجوع کرده و از راهحلهایی که قبلاً برای مسائل مشابه به کار بردهاند، استفاده میکنند. این روش تفکر در قالب جفتهای مسئله-راهحل، که به طور طبیعی در بسیاری از حوزهها همچون معماری، اقتصاد و مهندسی نرمافزار مشاهده میشود، روشی متداول برای مواجهه با مشکلات و تعاملات اجتماعی است. در کتاب "راه بیزمان ساختمان"، کریستوفر الکساندر، معمار برجسته، اصطلاح "الگو" را اینگونه تعریف میکند: هر الگو یک قاعده سهگانه است که رابطهای خاص را میان یک زمینه، یک مشکل و یک راهحل ارائه میدهد. از دیدگاه جهانشناسی، هر الگو یک رابطه است که میان یک زمینه خاص، سیستم نیروهایی که به طور مکرر در آن زمینه ظاهر میشوند و یک پیکربندی فضایی که به این نیروها اجازه میدهد تا خود را حل کنند، برقرار است. به زبان ساده، الگو نوعی دستورالعمل است که به ما نشان میدهد چگونه میتوان این پیکربندی فضایی را در موقعیتهای مختلف به کار برد تا نیروهای موجود در آن زمینه را حل کنیم. در واقع، الگو هم یک فرآیند است و هم یک شیء؛ هم توصیف یک شیء زنده و پویاست و هم توصیف فرآیندی است که آن را میسازد. در مهندسی نرمافزار نیز این الگوها بهطور گسترده استفاده میشوند. متخصصان این حوزه از طریق تجربیات عملی خود این الگوها را میشناسند و در فرآیند طراحی سیستمها از آنها برای حل مسائل پیچیده به روشی کارآمد و زیبا استفاده میکنند.
قبل از پرداختن به جزئیات این موضوع، ابتدا به یک مثال شناختهشده میپردازیم:
مثال مدل-نمایش-کنترلر این الگو را میتوان در هنگام توسعه نرمافزار با رابط کاربری کامپیوتری در نظر گرفت. رابطهای کاربری به دلیل درخواستهای مکرر تغییرات در معرض تغییرات زیادی قرار دارند. به عنوان مثال، زمانی که ویژگیهای جدیدی به یک برنامه افزوده میشود، منوها باید بهروزرسانی شوند تا به توابع جدید دسترسی داشته باشند و یا رابطهای کاربری باید برای مشتریان خاص سفارشیسازی شوند. علاوه بر این، ممکن است سیستم نیاز به انتقال به پلتفرم دیگری با استاندارد "ظاهر و احساس" متفاوت داشته باشد. حتی ارتقاء به نسخه جدیدی از سیستم پنجرهای میتواند موجب تغییرات در کد شود. در نتیجه، رابط کاربری یک سیستم با عمر طولانی میتواند بهطور مداوم تغییر کند. ساخت سیستمهایی با انعطافپذیری لازم، زمانی که رابط کاربری بهطور محکم با هسته عملکردی گره خورده باشد، هزینهبر و مستعد خطاست. در چنین شرایطی، توسعه و نگهداری چندین سیستم نرمافزاری متفاوت برای هر پیادهسازی رابط کاربری اجتنابناپذیر است و تغییرات در این سیستمها بهطور گسترده در بسیاری از ماژولها پخش میشود. بهطور کلی، هنگام توسعه سیستمهای نرمافزاری تعاملی، باید دو جنبه را مدنظر قرار داد:
- تغییرات در رابط کاربری باید آسان و در زمان اجرا ممکن باشد.
- تغییرات در رابط کاربری نباید بر کد هسته عملکردی برنامه تأثیر بگذارد.
برای حل این مشکل، یک راهحل مناسب این است که برنامههای تعاملی را به سه بخش تقسیم کنیم: پردازش، خروجی و ورودی:
- مدل دادهها و عملکردهای اصلی سیستم را در خود جای میدهد و از نمایشهای خاص خروجی یا رفتارهای ورودی مستقل است.
- مایشها اطلاعات را به کاربر نشان میدهند و دادههای خود را از مدل دریافت میکنند. ممکن است چندین نمایش مختلف از مدل وجود داشته باشد.
- هر نمایش یک کنترلر دارد که ورودیها را دریافت کرده و آنها را به درخواستهای خدماتی ترجمه میکند که یا به مدل یا به نمایش ارسال میشوند. کاربر تنها از طریق کنترلرها با سیستم ارتباط برقرار میکند.
تفکیک مدل از نمایش و کنترلر این امکان را فراهم میکند که چندین نمایش مختلف از یک مدل وجود داشته باشد. هرگاه کاربر مدل را از طریق کنترلر یک نمایش تغییر دهد، تمامی نمایشهای وابسته به آن داده باید تغییرات را منعکس کنند. برای دستیابی به این هدف، مدل به تمام نمایشها اطلاع میدهد که دادههای آن تغییر کرده است و نمایشها با دریافت دادههای جدید از مدل، اطلاعات خود را بهروزرسانی میکنند.
این راهحل به شما این امکان را میدهد که یک زیرسیستم از برنامه را بدون ایجاد تأثیرات عمده بر سایر زیرسیستمها تغییر دهید. به عنوان مثال، میتوان از یک رابط کاربری غیرگرافیکی به یک رابط کاربری گرافیکی انتقال داد بدون آنکه نیاز به تغییر در زیرسیستم مدل باشد. همچنین میتوان پشتیبانی از دستگاههای ورودی جدید را اضافه کرد بدون اینکه تأثیری بر نمایش اطلاعات یا هسته عملکردی سیستم بگذارد. تمامی نسخههای نرمافزار میتوانند بهطور مستقل از "ظاهر و احساس" خاص خود، بر روی همان زیرسیستم مدل عمل کنند.
از این مثال، ویژگیهایی از الگوها در معماری نرمافزار قابل استخراج است: الگوها به حل مشکلات طراحی مکرری پرداخته که در موقعیتهای خاص طراحی پدید میآیند و راهحلهایی برای آنها ارائه میدهند. در مثال مذکور، مشکل اصلی پشتیبانی از تنوع در رابطهای کاربری است که ممکن است در فرآیند توسعه سیستمهای نرمافزاری با تعامل انسان-کامپیوتر به وجود آید. این مشکل با تفکیک واضح مسئولیتها قابل حل است؛ به گونهای که هسته عملکردی سیستم از رابط کاربری آن جدا میشود.
الگوها، تجربیات طراحی اثباتشده و موجود را مستند میکنند و به طور مصنوعی ساخته نمیشوند. در حقیقت، الگوها بهعنوان راهی برای استخراج و استفاده مجدد از دانش طراحی به دست آمده توسط متخصصان با تجربه عمل میکنند. کسانی که با مجموعهای از الگوهای مناسب آشنا هستند، میتوانند آنها را بهطور مؤثر و بدون نیاز به کشف دوباره برای حل مشکلات طراحی به کار ببرند. به عبارت دیگر، الگوها دانش تخصصی را که قبلاً در ذهن تعداد کمی از متخصصان قرار داشته، بهطور عمومی در دسترس قرار میدهند. این امر به طراحان امکان میدهد تا نرمافزارهایی با کیفیت بالا برای اهداف خاص طراحی کنند. به عنوان مثال، الگوی مدل-نمایش-کنترلر، تجربی است که در طول سالها توسعه سیستمهای تعاملی به دست آمده است. بسیاری از برنامههای مشهور از این الگو بهره میبرند؛ این الگو معماری کلاسیک برای بسیاری از برنامههای Smalltalk است و همچنین زیرساخت چندین چارچوب کاربردی مانند MacApp یا ET++ میباشد.
الگوها انتزاعاتی را شناسایی و مشخص میکنند که فراتر از سطح کلاسها، نمونهها یا اجزاء فردی هستند. معمولاً یک الگو مجموعهای از اجزاء، کلاسها یا اشیاء را توصیف کرده و مسئولیتها، روابط و تعاملات آنها را توضیح میدهد. تمامی این اجزاء با همکاری یکدیگر، مسئلهای را که الگو به آن پرداخته است، حل میکنند و معمولاً این کار را بهطور مؤثرتری نسبت به یک جزء واحد انجام میدهند. به عنوان مثال، الگوی مدل-نمایش-کنترلر شامل مثلثی از سه جزء همکار است و هر مثلث MVC نیز با سایر مثلثهای MVC در سیستم همکاری میکند. الگوها زبان مشترک و درک پایهای از اصول طراحی را فراهم میکنند. در صورتی که نامگذاری الگوها به درستی انجام شود، آنها به بخشی از زبان طراحی رایج تبدیل میشوند. این الگوها به تسهیل بحثهای مؤثر در مورد مشکلات طراحی و راهحلهای آنها کمک میکنند. به جای اینکه برای توضیح یک راهحل خاص نیاز به شرح طولانی و پیچیده باشد، میتوان از نام الگو استفاده کرده و به توضیح اجزاء مختلف راهحل و ارتباطات میان آنها در چارچوب الگو پرداخت. به عنوان مثال، نام "مدل-نمایش-کنترلر" و الگوی مرتبط با آن از اوایل دهه 1980 در جامعه Smalltalk شناخته شده است و بسیاری از مهندسان نرمافزار از آن بهره میبرند. وقتی گفته میشود "معماری نرمافزار از الگوی مدل-نمایش-کنترلر پیروی میکند"، همکارانی که با این الگو آشنا هستند، بهسرعت از ساختار و ویژگیهای اصلی برنامه آگاهی پیدا میکنند.
الگوها بهعنوان ابزاری برای مستندسازی معماریهای نرمافزاری عمل میکنند. این الگوها میتوانند دیدگاه طراح هنگام طراحی یک سیستم نرمافزاری را بهطور واضح بیان کنند. این امر به دیگران کمک میکند تا هنگام گسترش یا تغییر معماری اصلی سیستم، یا اصلاح کد آن، از انحراف از این دیدگاه جلوگیری کنند. بهعنوان مثال، اگر بدانید که سیستم بر اساس الگوی مدل-نمایش-کنترلر طراحی شده است، میدانید که چگونه میتوان آن را برای افزودن یک عملکرد جدید گسترش داد، بهطوریکه هسته عملکردی از ورودیهای کاربر و نمایش اطلاعات جدا باقی بماند.
الگوها از توسعه نرمافزار با ویژگیهای مشخص پشتیبانی میکنند. این الگوها بهعنوان چارچوبهایی برای رفتارهای عملکردی عمل کرده و به پیادهسازی آنها در نرمافزار کمک میکنند. بهعنوان مثال، الگوهایی برای حفظ انسجام میان اجزاء همکار و فراهمسازی ارتباطات شفاف بین فرآیندها وجود دارند. علاوه بر این، الگوها بهطور خاص به نیازمندیهای غیرعملکردی نرمافزار، همچون قابلیت تغییر، قابلیت اطمینان، قابلیت آزمایش و قابلیت استفاده مجدد پرداختهاند. بهعنوان نمونه، الگوی مدل-نمایش-کنترلر از قابلیت تغییر در رابطهای کاربری و استفاده مجدد از هسته عملکردی پشتیبانی میکند.
الگوها به توسعه معماریهای پیچیده و ناهمگن نرمافزاری کمک میکنند. هر الگو مجموعهای از اجزاء از پیش تعریفشده، نقشها و روابط میان آنها را مشخص میکند و میتوان از آن برای تعریف جنبههای خاص ساختارهای نرمافزاری استفاده کرد. الگوها "بهعنوان بلوکهای ساخت برای طراحیهای پیچیدهتر عمل میکنند." این روش استفاده از آثار طراحی از پیش تعریفشده موجب تسریع و بهبود کیفیت طراحی میشود. درک و بهکارگیری الگوهای نوشتهشده بهطور دقیق، زمانی را در مقایسه با جستجو برای یافتن راهحلهای جدید ذخیره میکند. این بدین معنا نیست که الگوهای فردی همیشه بهتر از راهحلهای خود طراحان هستند، اما حداقل یک سیستم الگو مانند آنچه در این کتاب توضیح داده شده میتواند به طراحان کمک کند تا گزینههای مختلف طراحی را ارزیابی و تحلیل کنند.
با این وجود، علیرغم اینکه یک الگو ساختار اصلی راهحل برای یک مشکل طراحی خاص را تعیین میکند، اما راهحل کاملاً جزئی و دقیقی ارائه نمیدهد. الگوها بهجای ارائه یک ماژول آماده که بهطور مستقیم قابل استفاده باشد، یک طرح عمومی برای حل مجموعهای از مشکلات مشابه ارائه میدهند. بنابراین، شما باید این طرح را با توجه به نیازهای خاص و زمینههای طراحی هر پروژه پیادهسازی کنید. الگوها به ایجاد واحدهای مشابه کمک میکنند که ممکن است در ساختار کلی خود مشابه باشند، اما جزئیات ظاهری آنها ممکن است تفاوتهای زیادی داشته باشد. بهطور کلی، الگوها در حل مشکلات موثر هستند، اما راهحلهای کامل را بهتنهایی فراهم نمیکنند.
الگوها به مدیریت پیچیدگی نرمافزار کمک میکنند. هر الگو یک روش اثباتشده برای حل مشکل خاص خود توصیف میکند؛ این شامل نوع اجزاء مورد نیاز، نقشهای آنها، جزئیاتی که باید پنهان شوند، انتزاعاتی که باید نمایان باشند و نحوه تعامل آنها با یکدیگر است. هنگامی که با یک وضعیت طراحی مشخص روبهرو میشوید که توسط یک الگو پوشش داده شده است، نیازی به صرف زمان برای اختراع راهحلهای جدید نیست. در صورتی که الگو بهدرستی پیادهسازی شود، میتوان به راهحل آن اعتماد کرد. بهعنوان مثال، الگوی مدل-نمایش-کنترلر به شما کمک میکند تا جنبههای مختلف رابط کاربری یک سیستم نرمافزاری را از یکدیگر تفکیک کرده و انتزاعهای مناسب برای هرکدام فراهم آورید. در نهایت، میتوانیم تعریف زیر را ارائه دهیم: یک الگو برای معماری نرمافزار، یک مشکل طراحی خاص و تکراری را که در زمینههای طراحی مشخصی رخ میدهد توصیف میکند و یک طرح عمومی اثباتشده برای حل آن پیشنهاد میدهد. این طرح با توصیف اجزاء تشکیلدهنده، مسئولیتها و روابط آنها، و نحوه همکاری میان این اجزاء مشخص میشود.
ویژگیهای یک الگو
بحث ارائهشده در بخش قبلی ما را به پذیرش یک ساختار سهگانه هدایت میکند که اساس هر الگو را تشکیل میدهد:
- زمینه: شرایطی که باعث بروز یک مشکل میشود.
- مشکل: مشکلی که بهطور مکرر در آن زمینه بروز میکند.
- راهحل: یک راهحل اثباتشده برای رفع مشکل.
این ساختار بهطور کلی نوعی قاعده را نشان میدهد که ارتباطی میان زمینه خاص، مشکل موجود در آن زمینه، و راهحل مناسب برای آن برقرار میکند. تمامی اجزای این ساختار بهطور نزدیک به هم مرتبط هستند. با این حال، برای درک دقیق این ساختار، لازم است که مفهوم «زمینه»، «مشکل» و «راهحل» را بهطور کامل روشن کنیم.
زمینه
زمینه، چارچوبی فراتر از دوگانگی ساده مشکل-راهحل است که وضعیتهایی را توضیح میدهد که در آنها مشکل بهوجود میآید. زمینه یک الگو میتواند بهطور عمومی تعریف شود، مانند "توسعه نرمافزار با رابط کاربری انسان-کامپیوتر"، یا میتواند خاصتر باشد، مانند "پیادهسازی مکانیسم انتشار تغییرات در تریاد مدل-نمایش-کنترلر". تعیین زمینه مناسب برای یک الگو میتواند چالشبرانگیز باشد، چرا که شناسایی تمامی موقعیتهایی که ممکن است الگو در آنها کاربرد داشته باشد، تقریباً غیرممکن است. بنابراین، رویکرد عملیتر این است که لیستی از موقعیتهای شناختهشده تهیه شود که در آنها مشکلی که الگو به آن پرداخته است، رخ میدهد. این کار ممکن است تمامی موقعیتهای ممکن را پوشش ندهد، اما حداقل راهنماییهای مفیدی ارائه میدهد.
مشکل
این بخش از ساختار الگو، مشکلی را که بهطور مکرر در زمینه خاصی بهوجود میآید، توصیف میکند. مشکل بهطور ابتدایی با بیان مشخصات کلی آن آغاز میشود که ماهیت اصلی آن را بیان میکند و نشان میدهد که مشکل خاصی که باید حل شود، چیست. برای مثال، الگوی مدل-نمایش-کنترلر به مشکلی پرداخته است که رابطهای کاربری معمولاً تغییر میکنند. پس از بیان مشکل، مجموعهای از «نیروها» به توضیح بیشتر آن پرداخته میشود. این نیروها، که اصطلاحی هستند که از معماری قرض گرفته شدهاند، به جنبههای مختلف مشکل اشاره میکنند که هنگام حل آن باید در نظر گرفته شوند. نیروها میتوانند شامل نیازها، محدودیتها و ویژگیهای مطلوب باشند. بهعنوان مثال، در الگوی مدل-نمایش-کنترلر، یکی از نیروها این است که تغییرات رابط کاربری باید آسان باشد، اما در عین حال نباید هسته عملکردی نرمافزار تحت تأثیر قرار گیرد.
راهحل
قسمت «راهحل» در یک الگو نحوه حل مشکل تکراری یا به عبارتی، نحوه متعادلسازی نیروهای مرتبط با آن را نشان میدهد. در معماری نرمافزار، این راهحل شامل دو جنبه است که برای حل مشکل بهطور مؤثر به هم پیوستهاند. این جنبهها به نحوه سازماندهی اجزای سیستم و نحوه تعامل و همکاری آنها برای دستیابی به یک راهحل جامع اشاره دارند. در ابتدا، هر الگو یک ساختار خاص را مشخص میکند، که شامل یک پیکربندی فضایی از اجزاء است. بهعنوان مثال، در توضیح الگوی مدل-نمایش-کنترلر، عبارت «یک برنامه تعاملی را به سه بخش پردازش، خروجی و ورودی تقسیم کنید» آمده است. این ساختار به جنبههای ایستا (ثابت) راهحل پرداخته و مشابه میکرو-معماریها عمل میکند. این میکرو-معماری از اجزاء و روابط میان آنها تشکیل شده است. در چنین ساختاری، اجزاء بهعنوان بلوکهای سازنده عمل کرده و هر جزء مسئولیت خاصی دارد. روابط بین اجزاء نیز جایگاه و تعامل آنها را تعیین میکند.
دومین جنبهای که هر الگو تعریف میکند، رفتار زمان اجرا است. برای مثال، در بخش راهحل الگوی مدل-نمایش-کنترلر، گفته میشود: «کنترلرها ورودی دریافت میکنند، معمولاً بهصورت رویدادهایی که نشاندهنده حرکت ماوس، فعالسازی دکمههای ماوس یا ورودی از صفحهکلید هستند. این رویدادها به درخواستهای خدماتی تبدیل شده و به مدل یا نمایش ارسال میشوند.» این بخش به جنبههای پویا (دینامیک) راهحل پرداخته و نحوه همکاری، سازماندهی کار و ارتباطات بین اجزاء را توضیح میدهد.
لازم به ذکر است که راهحل یک الگو لزوماً تمامی نیروهای مرتبط با مشکل را حل نمیکند. در واقع، ممکن است الگو بر روی نیروهای خاصی تمرکز کرده و برخی دیگر را نادیده بگیرد یا بهطور کامل حل نکند، بهویژه اگر نیروها با یکدیگر در تضاد باشند.
در نهایت، همانطور که پیشتر اشاره شد، الگوها یک طرح راهحل ارائه میدهند نه یک راهحل کاملاً مشخص. این طرحها میبایست در پیادهسازیهای مختلف قابل استفاده باشند، بهطوری که ماهیت اصلی آن حفظ شود. در واقع، الگوها بهعنوان بلوکهای ساختاری ذهنی عمل میکنند. پس از استفاده از یک الگو، معماری نرمافزاری باید ساختار خاصی را در بر داشته باشد که نقشهای تعریفشده توسط الگو را فراهم کرده، اما آنها را بر اساس نیازهای خاص مسئله تنظیم و تطبیق دهد. در این راستا، هیچ دو پیادهسازی از یک الگو بهطور کامل مشابه نخواهند بود.