مقدمه‌ای بر معماری MVC

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

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

خلاصه آن که امروز نشستم و درسی از کتاب را که به معرفی معماری MVC اختصاص داشت، نوشتم و آنچه در ادامه خواهید، همان نوشته است که به‌زودی در کتاب نیز ظاهر خواهد شد.

ورود به مطلب

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

  • حرف M، ابتدای واژه‌ی Model است که ما آن را «مدل» می‌خوانیم.
  • حرف V، ابتدای واژه‌ی View است که ما آن را «نمایش» می‌خوانیم.
  • حرف C، ابتدای واژه‌ی Controller است که آن را «کنترل» می‌خوانیم.

لایه مدل

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

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

لایه‌ی مدل را نباید دیتابیس یا دروازه‌ی ارتباط با سامانه‌ای دیگر در نظر گرفت. لایه‌ی مدل، محلی است برای کار با داده‌ها، به معنای عام کلمه، بدون آن که از دلیل استفاده از داده‌ها بپرسد و اما و اگری بیاورد.

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

لایه نمایش

درک لایه‌ی نمایش، از همه ساده‌تر است. این لایه همان است که رابط کاربری را رقم می‌زند و ابتدا و انتهای چرخه‌ی برنامه است.

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

تأکید می‌کنم لایه‌ی نمایش، آنچنان که از نامش برمی‌آید، تنها به خروجی برنامه اختصاص ندارد و شامل ورودی نیز می‌شود.

لایه کنترل

لایه‌ی کنترل، رگ حیاتی برنامه است که اجزای آن را به یکدیگر متصل می‌سازد. درخواستی که کاربران از طریق لایه‌ی نمایش صادر کرده‌اند، در لایه‌ی کنترل وصول می‌شود، به مسیر درست هدایت می‌شود، اعتبارسنجی‌های لازم (به کمک لایه‌ی مدل) روی آن صورت می‌گیرد، و اگر مشکلی نباشد نهایتاً برای ذخیره‌سازی یا استخراج به لایه‌ی مدل ارسال می‌شود و نتیجه‌ها یا بازخوردهای آن دوباره به لایه‌ی نمایش بازگردانده می‌شود تا به اطلاع کاربر برسد.

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

ارتباط بین لایه‌ها

پرسشی که بی‌درنگ پس از مشخص شدن وظیفه‌ی هر لایه مطرح می‌شود این است که لایه‌ها چگونه و در چه شرایطی می‌توانند با یکدیگر ارتباط برقرار نمایند.

فابیو چِواسکو در مقاله‌ی خود با عنوان نخستین لقمه از کیک‌پی‌اچ‌پی، می‌گوید:

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

آنچه چواسکو از ارتباط میان لایه‌ها در نظر دارد چیزی شبیه این شکل است:

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

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

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

اختلاف‌نظرها پایان‌ناپذیرند

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

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

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

در یک مثال واقعی

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

ابهام‌ها با یک مثال خوب روشن‌تر می‌شوند.

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

پرده اول

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

پرده دوم

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

پرده سوم

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

در این‌جا پس از عبور از لایه‌ی نمایش (فرم و مدارک)، لایه‌ی کنترل شروع به اعتبارسنجی اطلاعات موجود می‌کند (بررسی تکمیل فرم) که ممکن است دو حالت پیش بیاید:

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

یک بار مرور کنیم...

لایه‌ی نمایش همان فرم‌هایی بود که پر کردیم و رسیدهایی که تحویل گرفتیم.

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

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

به این نکته هم توجه کنید که لایه‌ی مدل، بدون توجه به دلیل مسدودی کارت، این کار را انجام داد. برای لایه‌ی مدل همین کافی بود که چنین درخواستی داده شده است تا اجرا کند.

این چه وضعی است؟

اگر عابری در خیابان همین فرمان را به لایه‌ی مدل می‌فرستاد باز هم کارت بانکی شما مسدود می‌شد؟

پاسخ مثبت است!

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

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

قضاوت در مورد MVC

استفاده از معماری MVC در برنامه‌ها مزیت‌هایی به همراه دارد:

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

اما MVC نیز مثل هر چیز دیگر این دنیا، سراسر خیر نیست و مشکلاتی را هم به همراه می‌آورد.

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

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

نتیجه

معماری MVC در خلاصه‌ترین توصیف ممکن، به این شکل تعریف می‌شود:

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

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



این متن، به صورت Markdown نوشته شده بود و وقتی آن را در محیط ویرگول paste کردم، تیترها و لینک‌ها، بدون دستکاری من، به‌خوبی منتقل شدند. باید اعتراف کنم که انتظارش را نداشتم. (: