فصل اول: پیش به سوی صفر
معماری MVC
در مقدمه گفتیم و از نام کتاب هم پیداست که فرآیند آموزش از نقطهی صفر شروع میشود و لازم نیست چیزی دربارهی لاراول بدانید.
اما به پیشنیازهایی هم اشاره کردیم که قرار شد در هر کدام از درسهای فصل یک کتاب، یکی از آنها را بشکافیم.
این فصل به همین موضوع اختصاص دارد و در درس اول، مفهوم جداسازی لایهها به شیوهی MVC را میشکافیم.
اگر با موضوعهای ارائهشده در این فصل آشنا هستید، بهتر است وقت خود را تلف نکنید و بدون مطالعه، از آن عبور کنید. فصلهای بعدی به مطالب این فصل وابسته نیستند.
تعریف ساده
معماری سه لایهی MVC، ایدهای از ساخت برنامهها است که در آن، فرآیند اجرایی برنامه به سه بخش متفاوت و مستقل از یکدیگر تقسیم میشوند.
- حرف M، ابتدای واژهی Model است که ما آن را «مدل» میخوانیم.
- حرف V، ابتدای واژهی View است که ما آن را «نمایش» میخوانیم.
- حرف C، ابتدای واژهی Controller است که آن را «کنترل» میخوانیم.
لایه مدل
مدل، لایهای از برنامه است که به ذخیرهی دائمی دادههای برنامه اختصاص دارد و به بیانی شفافتر، با دیتابیس در ارتباط است. پردازش دادهها، چه پیش از ذخیرهی آنها و چه پس از آن در هنگام استفاده، بر عهدهی لایهی مدل است.
مهم است بدانیم مدلها در این معماری، نسبت به آنچه در بیرونشان روی میدهد، نابینا هستند. این که دادههایی که ذخیره میشوند از کجا و به چه طریقی به دست آمدهاند و این که دادههایی که استخراج میشوند قرار است به چه کار آیند، به مدل ارتباطی ندارد. لایهی مدل نه این چیزها را میداند و نه در طلب دانستن آنها، ارتباطی با دیگر لایهها برقرار میکند.
مدلها را نباید «دیتابیس» یا «دروازه»ی ارتباط با سامانهای دیگر در نظر گرفت. لایهی مدل، محلی است برای کار با دادهها، به معنای عام کلمه، بدون آن که از دلیل استفاده از دادهها بپرسد و اما و اگری بیاورد.
از آنجا که دادهها قلب هر نرمافزاری هستند، مدلهای یک برنامه، اغلب پیچیدهترین قسمت هر برنامه قلمداد میشوند که پردازشهای اصلی در آنجا روی میدهد.
لایه نمایش
درک لایهی نمایش، از همه سادهتر است. این لایه همان است که رابط کاربری را رقم میزند و ابتدا و انتهای چرخهی برنامه است.
در واقع کاربران از این لایه با برنامه ارتباط برقرار میکنند و دادههایی را وارد میکنند و سپس در همین لایه نتیجه را مشاهده مینمایند. در نرمافزارهای تحت وب، همچون محصولاتی که با پیاچپی خلق میشوند، لایهی نمایش همان است که با تگهای html ساخته میشود و با استفاده از استایلهای css زیبا میشود.
تأکید میکنم لایهی نمایش، آنچنان که از نامش برمیآید، تنها به خروجی برنامه اختصاص ندارد و شامل ورودی نیز میشود.
لایه کنترل
لایهی کنترل، رگ حیاتی برنامه است که اجزای آن را به یکدیگر متصل میسازد. درخواستی که کاربران از طریق لایهی نمایش صادر کردهاند، در لایهی کنترل وصول میشود، به مسیر درست هدایت میشود، اعتبارسنجیهای لازم (به کمک لایهی مدل) روی آن صورت میگیرد، و اگر مشکلی نباشد نهایتاً برای ذخیرهسازی یا استخراج به لایهی مدل ارسال میشود و نتیجهها یا بازخوردهای آن دوباره به لایهی نمایش بازگردانده میشود تا به اطلاع کاربر برسد.
باید توجه داشت که در یک برنامهی تحت وب، همهی درخواستهای کاربران لزوماً از لایهی نمایش عبور نمیکنند. اگر از APIها که اساساً لایهای به عنوان لایهی نمایش ندارند نیز بگذریم، بسیاری اوقات شما با کلیک بر لینکی که از قبل و توسط شخصی دیگر مهیا شده وارد برنامه میشوید و به این صورت، بدون عبور از لایهی نمایش، درخواست خود را مستقیماً به لایهی کنترل میفرستید.
ارتباط بین لایهها
پرسشی که بیدرنگ پس از مشخص شدن وظیفهی هر لایه مطرح میشود این است که لایهها چگونه و در چه شرایطی میتوانند با یکدیگر ارتباط برقرار نمایند.
فابیو چِواسکو در مقالهی خود با عنوان نخستین لقمه از کیکپیاچپی، میگوید:
پیادهسازی درست معماری MVC، مستلزم آن است که هیچ ارتباطی بین لایههای مدل و نمایش وجود نداشته باشد و تمام کارهای منطقی توسط لایهی کنترل انجام شود.
آنچه چواسکو از ارتباط میان لایهها در نظر دارد چیزی شبیه این شکل است:
این نظر او، مخالفین سفت و سختی دارد. بسیاری معتقدند که نهتنها لایهی نمایش میتواند با لایهی مدل ارتباط برقرار کند و آنچه مایل است را دریافت نماید، بلکه این تنها لایهی نمایش است که اجازهی چنین کاری را دارد.
طرفداران دیدگاه دوم معتقدند که درخواستها از طریق لایهی کنترل مسیریابی میشوند و به لایهی مدل میرسند و نتیجهی کار در لایهی نمایش به دست کاربر میرسد.
منتقدان نظریهی دوم میگویند که این ایده، ناقض اصلی است که طی آن مدل باید چشم و گوش بسته به فرمانها عمل کند و بدون توجه به مرجع و منبع درخواستها، نسبت به برآورده ساختن دستورات اقدام کند، چرا که در این طرح ارتباطی، مدلها دستور خود را از جایی (کنترل) میگیرند و پاسخ را به جای دیگری (نمایش) میفرستند و به این ترتیب، خودشان جزئی از مسیر برنامه میشوند.
اختلافنظرها پایانناپذیرند
اجازه دهید ادامهی این دعوا و نظریههای دیگر را به اهل فن واگذار کنیم و شما هم اگر کنجکاو شدهاید، قدر کنجکاوی خود را بدانید و تحقیق در این زمینه را در منابع تخصصیتر پیگیری کنید.
به هر حال، نرمافزار ما در معماری MVC، به سه لایهی مستقل تقسیم میشود که هر لایه کار مربوط به خود را در فضایی تقریباً مستقل از دیگران به انجام میرساند و خوشبختانه در مورد ماهیت وظیفهی هر یک از این لایهها اختلاف نظری وجود ندارد.
این اندازه بدانید که لاراول، به عنوان یک فریمورک [تقریباً مبتنی بر] MVC، در مورد ارتباط لایهها چندان سختگیر نیست و به لایهها اجازهی ارتباط با یکدیگر را میدهد، اما ایدهآل همان است که فابیو چواسکو میگوید.
یک مثال واقعی
معماری نرمافزار با سبک MVC، در ابتدا از زبان برنامهنویسی اسمالتاک آغاز شد و در برنامههای وب به اوج رسید، اما باید بدانیم تقسیم کار به این نحو، محدود به این نرمافزار و آن نرمافزار، و یا حتی محدود به دنیای نرمافزار نیست.
ابهامها با یک مثال خوب روشنتر میشوند.
مطمئنم برای کارهای مختلف گذارتان به بانکها افتاده است. بانک مثال ما ممکن است کمی با بانکهای واقعی متفاوت باشد، اما مراد ما را برآورده میسازد.
پرده اول
فرض کنید برای مسدود کردن کارت عابربانکتان به یکی از شعبههای بانک خود میروید. از در شعبه وارد میشوید و شمارهای میگیرید و وقتی نوبتتان فرا رسید به یکی از باجهها میروید.
این درست مانند آن است که به سایتی بروید و روی یکی از گزینههای منو کلیک کنید و به صفحهای که مرتبط با کار شماست هدایت شوید.
در اینجا تقاضای خود را در لایهی نمایش (دستگاه نوبتدهی) ثبت کردهاید و سپس از طریق لایهی کنترل (فرآیند پشت پردهی نوبتدهی) به باجهی مربوطه هدایت شدهاید.
پرده دوم
پشت باجه روی صندلی مینشینید و درخواستتان را مطرح میکنید و یک فرم به شما میدهند تا تکمیل کنید.
این درست مانند آن است که در صفحهای که هدایت شدهاید با یک فرم اینترنتی روبهرو شوید.
در این جا بار دیگر تقاضای خود را به لایهی کنترل (متصدی باجه) گفتهاید و او بدون نیاز به مراجعه به لایهی مدل (سوابق اطلاعاتی شما) ، لایهی نمایش را فراخوانی کرده است (فرم).
پرده سوم
فرم را پر میکنید و همراه با کارت ملی به متصدی باجه تحویل میدهید و او شروع به بررسی میکند تا همهی موارد را پر کرده باشید، تاریخ درست درج کرده باشید، و اطلاعاتی که روی فرم نوشتهاید با کارت ملی شما مطابقت داشته باشد و تصویر روی کارت با چهرهی شما وفق کند و سپس شروع به درج اطلاعات در کامپیوترش میکند و اگر همه چیز مرتب باشد و کار انجام شود، رسیدی به شما میدهد.
در اینجا پس از عبور از لایهی نمایش (فرم و مدارک)، لایهی کنترل شروع به اعتبارسنجی اطلاعات موجود میکند (بررسی تکمیل فرم) که ممکن است دو حالت پیش بیاید:
- اگر مشکلی وجود داشته باشد دوباره لایهی نمایش فراخوانی میشود (فرم را به شما بازمیگردانند تا اصلاح کنید)
- اگر همه چیز مرتب بود، اطلاعات توسط متصدی باجه روانهی لایهی مدل میشوند (همان درج در کامپیوتر) و نتیجهای که لایهی مدل میدهد توسط لایهی کنترل (آقا یا خانم متصدی باجه) به شما تحویل میشود و این همان رسیدی (لایهی نمایش) است که تحویل گرفتهاید.
یک بار مرور کنیم...
لایهی نمایش همان فرمهایی بود که پر کردیم و رسیدهایی که تحویل گرفتیم.
نقش لایهی کنترل را متصدی باجه بر عهده داشت که بدون دسترسی به اطلاعات ما، با شنیدن درخواستمان فرم درست را در اختیارمان گذاشت و بعد پس از اطمینان از صحت تکمیل فرم، سراغ درج اطلاعات (لایهی مدل) رفت.
لایهی مدل مثال ما، در کامپیوتر جلوی روی متصدی باجه نهفته بود. ما به عنوان کاربر به آن دسترسی نداشتیم و خود متصدی باجه نیز اجازه نداشت مستقیماً به بایگانی بانک برود و اطلاعات را استخراج کند یا چیزی به پرونده اضافه نماید. او متدی از متدهایی که لایهی مدل در اختیار او گذاشته بود را فراخوانی کرد و نتیجهی آن را به ما گفت.
به این نکته هم توجه کنید که لایهی مدل، بدون توجه به دلیل مسدودی کارت، این کار را انجام داد. برای لایهی مدل همین کافی بود که چنین درخواستی داده شده است تا اجرا کند.
یک چالش امنیتی
اگر عابری در خیابان همین فرمان را به لایهی مدل میفرستاد باز هم کارت بانکی شما مسدود میشد؟
پاسخ مثبت است!
لایهی مدل کاری به هویت درخواستکننده ندارد و فرمانها را اجرا میکند. تأمین امنیت بر عهدهی لایهی کنترل است و دقیقاً به همین دلیل بهتر است معماری ما طوری پیادهسازی شود که لایهی نمایش نتواند دستوری به لایهی مدل بدهد و اگر به هر دلیل راهی پیدا کرد و این دستور را صادر کرد، درست مانند آن است که رخنهای امنیتی روی داده باشد.
لایهی کنترل، ممکن است برای اجرای وظیفهی امنیتی خود از لایهی مدل کمک بگیرد. مثلاً اطلاعات متصدی باجه را آنچه در پروندهی اوست مطابقت دهد. در این صورت هم خود به سراغ اطلاعات نمیرود و از متدی دیگر در لایهی مدل کمک میخواهد.
قضاوت در مورد MVC
استفاده از معماری MVC در برنامهها مزیتهایی به همراه دارد:
- بخشهای مختلف نرمافزار میتوانند توسط برنامهنویسان مختلفی تکمیل شوند.
- برنامهنویسان میتوانند به طور همزمان روی بخشهای خود کار کنند.
- بخشهای مرتبط با هم، انسجام بیشتری با یکدیگر دارند.
- وابستگی بخشها به عملکرد یکدیگر در حداقل ممکن قرار میگیرد.
- ویرایش برنامه سادهتر انجام میشود.
- میتوان بدون دست زدن به لایههای دیگر، چندین ظاهر مختلف (لایهی نمایش) برای مشتریهای مختلف تدارک دید.
از مشکلات هم بگوییم
MVC نیز مثل هر چیز دیگر این دنیا، سراسر خیر نیست و مشکلاتی را هم به همراه میآورد.
- تمام کارهای مرتبط با یک موضوع، در یک واحد از برنامه در کنار هم اجرا نمیشوند.
- پیچیدهتر شدن لایهها و ارتباط آنها، دنبال کردن کد را دشوار میکند.
- معماری مبتنی بر MVC، به چندین تخصص مختلف نیاز دارد که اغلب در یک نفر جمع نمیشوند.
- خلاصه کردن سراسر فرآیند به همین سه لایه، محدودیتهای زیادی میآفریند.
نتیجه
معماری MVC در خلاصهترین توصیف ممکن، به این شکل تعریف میشود:
- هیچ لایهای غیر از مدل حق دسترسی به اطلاعات دیتابیس را ندارد.
- هیچ لایهای غیر از نمایش حق ارتباط با کاربر را ندارد.
- هیچ لایهی غیر از کنترل، اجازهی مسیرسازی میان بخشهای مختلف را ندارد.
همان طور که میبینید، گاهی توصیفهای سلبی بهتر از شرح مستقیم یک چیز عمل میکنند.
لاراول و معماری MVC
اگرچه بسیاری لاراول را یک فریمورک مبتنی بر معماری MVC میشناسند و در زمان نگارش این جملهها، حتی صفحهی ویکیپدیای انگلیسی نیز لاراول را فریمورکی مبتنی بر MVC قلمداد میکند، خالق لاراول با این عقیده همداستان نیست.
به این گفتوگوی توییتری نگاه کنید:
تیلور اوتول لاراول را مبتنی بر MVC نمیداند و وقتی از او میپرسند که آیا اساساً MVC را به عنوان یک معماری خوب، یا حتی یک معماری قبول دارد یا خیر، تردید دارد و تعاریف MVC را محدودکننده میداند و نهایتاً میگوید:
تنها مشکل من با معماری MVC، حرف M آن است، چرا که مردم [مدل] را با دیتابیس اشتباه میگیرند.
خالی از لطف نیست اگر توییت دیگری از تیلور اوتول را نیز که به قضاوت MVC میپردازد بررسی کنیم.
در اینجا میگوید:
واقعاً فکر میکنم عبارت MVC در توسعه به شکلی باورنکردنی بیفایده شده است و باید به جای آن، «جداسازی مفاهیم» را آموزش دهیم.
مزایای جداسازی لایهها آن قدر زیاد هست که به دردسرهایش بیارزد و اگر بخواهیم آن را بهکلی کنار بگذاریم، بهتر است با چیز واقعاً بهتری جایگزین کنیم.
عجالتاً لاراول، که در این کتاب در پی آموختن آن داریم، نسخهای مخصوص به خود را ترویج میکند که به نحوی عبور از MVC محسوب میشود. اما به هر حال، مهم است بدانیم که از چه چیزی عبور میکنیم و پس از عبور، چگونه لایههای برنامه را همچنان از یکدیگر جدا نگاه داریم.
با تمام این اوصاف، شیوهی لاراول از جداسازی لایهها را میتوانیم الگوگرفته از معماری MVC بدانیم.
واقعیت آن است که لاراول لایههایی جدید بر MVC سنتی افزوده که به مرور با آنها آشنا میشویم و بهتر است حالا ذهن خود را درگیر آن نکنید.