احسان ولی نوری داور پنجمین جشنواره وب ایران


.
 
دانش خود را منتشر کنید

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

ورود
  
 
 
 
عضویت
رمز عبورتان را فراموش کرده اید؟

تبلیغات


.


حمایت از پی سی پدیا




.
  
Linkbox
 ادامه...
 
 
 ۱۳۹۳ چهارشنبه ۲۶ شهريور . ورود

 
 
 
ارسال شده توسط:PCPedia
تعداد دفعات بازدید:3564
تاریخ ثبت مقاله:۱۳۸۸ يکشنبه ۲۴ خرداد
امتیاز مقاله:4.66666666666667
تاریخ آخرین ویرایش:۱۳۸۸ جمعه ۲۹ خرداد
آخرین ویرایشگر:Ehsan
تعداد دفعات ویرایش:5
 

 نگاهی به برنامه نویسی جنبه گرا و پیدایش آن 
شايد قبلاً نام AOP (سرنام Aspect Oriented Programming) را شنيده باشيد. بسياري از ما اولين بار كه اين نام را شنيديم با تصور اين كه AOP نيز يكي از آن پارادايم‌هايي است كه هر چند سال يكبار براي جايگزيني برنامه‌نويسي شيء‌گرا مطرح مي‌شوند، بي‌تفاوت آن را كنار گذاشتيم. اما داستان AOP، طولاني‌تر از اين حرف‌ها است. زمان آن رسيده كه كمي خاك شيوه برنامه‌نويسي خود را بگيريد. مكاشفات جذابي وجود دارد...
موضوع مقاله: مفاهیم برنامه نویسی

مقدمه:
شايد قبلاً نام AOP (سرنام Aspect Oriented Programming) را شنيده باشيد. بسياري از ما اولين بار كه اين نام را شنيديم با تصور اين كه AOP نيز يكي از آن پارادايم‌هايي است كه هر چند سال يكبار براي جايگزيني برنامه‌نويسي شيء‌گرا مطرح مي‌شوند، بي‌تفاوت آن را كنار گذاشتيم. اما داستان AOP، طولاني‌تر از اين حرف‌ها است. زمان آن رسيده كه كمي خاك شيوه برنامه‌نويسي خود را بگيريد. مكاشفات جذابي وجود دارد...


بسياري از افراد معتقدند، علوم كامپيوتر آن قدرها هم كه به‌نظر مي آيد، سريع پيشرفت نمي‌كند. آن‌ها معتقدند، در بسياري از شاخه‌ها كار تقريباً تمام شده‌است و كارهاي جديد فقط در حد پيشرفت‌هاي جزئي انجام مي‌گيرد. در حقيقت، بعضي از موضوع‌هاي مطرح شده توسط اين گروه بدبين، تا حدودي به واقعيت نزديك است.

بسياري از پايه‌هاي علوم كامپيوتر شكل گرفته است و به نظر ميآيد تغيير آن‌ها، دست‌كم به اين زودي‌ها امكان‌پذير نيست. در بعضي از شاخه‌ها يك فناوري آن‌چنان جاي پايش را محكم كرده‌است كه حتي تصور وجود روشي ديگر كمي سخت به نظر مي‌رسد.

اما كامپيوتري‌ها مردم جالبي هستند. شايد آن‌ها خيلي پركار نباشند، اما هميشه ايده‌هاي جديد و خلاقانه راهي براي نفوذ به درون دنيايشان پيدا مي‌كنند. شايد در بسياري از زمينه‌ها، كار شما به مطالعه كارهاي كلاسيك انجام شده محدود شود، اما هميشه جاده‌هاي جديدي وجود دارد.

گريگور كيزالس (Gregor Kiczales)، بيشتر وقت خود را در آزمايشگاه پارك (PARC) كه مبدأ شروع بسياري از خلاقيت‌هاي بزرگ حوزه علوم كامپيوتر بوده، گذرانده است. محيط صنعتي - آكادميك آزمايشگاه علاوه بر دل‌مشغولي‌هاي آكادميك، كيزالس را به مسائل و مشكلات حوزه نرم‌افزار در دنياي واقعي آشنا ساخته است.

در حقيقت، يكي از همين مشكلات (Cross-cutting Concern) بود كه منجر به ارائه مدل AOP توسط اين پروفسور دانشگاه UBC و همكارانش در زيراكس پارك شد. مدلي كه به تحركات زيادي در حوزه  نرم‌افزار منجر شد تا جايي كه Daniel Sabbah، معاون بخش استراتژي‌هاي نرم‌افزاري شركت آي‌بي‌ام درباره آن مي‌گويد: «زمان توسعه نرم‌افزارها به وسيله مفهوم Aspect-Oriented فرا رسيده‌است. صنعت نرم‌افزار به آن نياز دارد و آي‌بي‌ام در حال حاضر از آن استفاده مي‌كند.»

اولين ارائه  رسمي از اين موضوع به سال 1997 برمي‌گردد. البته، اطلاعات تاريخي درباره AOP بسيار اندك است و ما از روند كار چيز زيادي نمي‌دانيم. كيزالس خود در پاسخ به پرسش نگارنده پيرامون تاريخچه و روند شكل‌گيري AOP مي‌گويد: «متأسفانه هيچ تاريخ مدوني براي AOP وجود ندارد.»

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

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

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

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

در سال 1972 پارانز مفهومی به نام جداسازی دغدغه‌ها را مطرح کرده که امروزه جزء مفاهیم اساسی در فرآیند مهندسی نرم‌افزار به شمار می‌آید. این مفهوم به صورت زیر تعریف شده است:
"قابلیت تشخیص، کپسوله‌سازی و کار با دغدغه، هدف و یا مقصود هستند"
دغدغه را می‌توان به عنوان محرکی برای تقسیم نرم‌افزار به بخش‌های قابل مدیریت درنظر گرفت. برای نمونه، یک وظیفه‌مندی خاص نرم افزار و مسائلی که به خواسته‌های غیروظیفه‌مندی مرتبط می‌شوند مانند ثبت وقایع، امنیت و غیره، همگی به عنوان دغدغه هستند، البته با توجه به جداسازی دغدغه‌ها آنها را در قالب واحدهای مستقل کپسوله کرده‌اند.

در سال 1997، مشهورترین رویکرد زبان جنبه‌گرا به نام AspectJ ابتدا توسط گروهی درXerox PARC عمومیت یافت. این گروه روی پروتکل‌ها و ایده‌ی مدل‌سازی دغدغه‌های مشترک کار می‌کردند. در همان حال، گروهی در شرکت IBM برنامه‌نویسی موضوع‌گرا را مطرح کردند. برنامه‌نویسی موضوع‌گرا و عناوین بعدی آن، تحت نام "جداسازی چندبعدی دغدغه‌ها"، به جداسازی و ادغام پیمانه‌های مختلف برنامه‌نویسی بر پایه‌ی دغدغه‌هایی در ابعاد مختلف پرداخته‌اند. [1]

نخستین کار در دانشگاه Twente هلند انجام یافت که در مورد فیلترهای ادغام‌سازی کار می‌کردند. به طوری که در پیاده‌سازی فیلترهایی که رفتار شی را در اجرا پیشرفت می‌دادند دخیل بودند. در دانشگاه Northeastern نیز انتزاعی از ساختار کلاس‌ها انجام گرفت که پشتیبانی بهتری از مفهوم دانش و رفتار عملیاتی ارائه می‌داد. در سال 1997، کریستیانا لوپز از هر دو مقاله استفاده کرد و زبان D-Java را به عنوان اولین مجموعه‌ی رسمی از زبان جنبه‌گرا ارائه نمود.

شیوه‌ی موضوعی اولین روشی بود که مفاهیم جنبه‌گرایی را با زبان مدل‌سازی یکپارچه ادغام کرد. این کار مشترکی از چندین گروه با گروه برنامه‌نویسی موضوع‌گرا است. برنامه‌نویسی موضوع‌گرا به طراحی موضوع‌گرا تبدیل شده و در سال 2001 به Theme/UML تبدیل گردید. تعریف و نمایش دغدغه‌ها برای نخستین بار در مستندات الیسا و گیل مورفی از دانشگاه British Columbia ارائه شد و در سال 2003 به عنوان بخشی از شیوه‌ی موضوعی طراحی جنبه‌گرا به نام Theme/Doc مطرح گردید.

حدود یک دهه‌ی قبل، به دنبال موفقیت درخور توجه ابزار CASE ، چیکوفسکی و کراس مبحث مهندسی معکوس و بازیابی طراحی را مطرح نمودند. تعریفی که آنها از مهندسی معکوس داشتند در زیر ارائه شده است:
"مهندسی معکوس، تحلیل یک سیستم به منظور تشخیص اجزا، ترکیبات فعلی، روابط بینابین آنها، استخراج و تولید تجریدهای موجود در سیستم و داده‌های مربوط به طراحی است." [2]
در دو دهه‌ی قبل، محققان امکاناتی را به منظور کشف، اعمال تغییر، تحلیل، جمع‌بندی، تولید، تجزیه و به تصویر کشیدن محصولات نرم‌افزاری ابداع کردند. این امکانات شامل تهیه‌ی اسناد نرم‌افزاری در شکل‌های گوناگون، نمایش کد میانی، داده و معماری بود. اغلب ابزارهای مهندسی معکوس بر استخراج ساختار درونی سیستم موجود با هدف انتقال آن به ذهن مهندس نرم افزار تمرکز دارد. در هر صورت، این ابزارها راه زیادی در پیش دارند تا به مرحله‌ای برسند که مورد استفاده‌ی روزانه‌ی مهندسان نرم‌افزار قرار گیرند. مطالعه و درک برنامه در صنعت نرم‌افزار به منظور کنترل هزینه و ریسک چرخه‌ی تحولات سیستم‌های نرم‌افزاری از اهمیت بالایی برخوردار می‌باشد.

چرا از پارادايم استفاده مي‌كنيم؟
توماس كوهن، پارادايم را اين‌گونه تعريف مي‌كند: «پارادايم در نتيجه فعاليت‌هاي اجتماعي ظاهر مي‌شود كه در آن مردم ايده‌هايشان را توسعه مي‌دهند و قواعد و مثا‌ل‌هايي مي‌سازند كه اين ايده‌ها را بيان كند.1» اين شايد يكي از رسمي‌ترين تعريف‌هايي باشد كه در سراسر عمرتان براي پارادايم مي‌شنويد. اما اين جمله زيبا براي يك برنامه‌نويس چه معنايي دارد؟

كامپيوترهاي اوليه توسط كدهاي باينري برنامه‌ريزي مي‌شدند و برنامه‌نويس، با ارسال دنباله‌اي از صفر و يك ها به پردازنده مركزي به‌طور مستقيم براي آن كامپيوتر برنامه‌نويسي مي‌كرد. با گذشت زمان، زبان‌هايي با سطوح بالاتر عرضه شدند.

اسمبلي، C و جاوا نمونه‌اي از زبان‌هاي نسل‌هاي مختلف هستند. با معرفي هر نسل، نحوه نوشتن برنامه و نگرش به مفاهيم نيز در آن تغيير مي‌يافت. ارائه شيوه‌هاي جديد توليد نرم‌افزار به اميد ايجاد راه‌هاي بهتر براي طراحي و پياده‌سازي يك برنامه، هنوز نيز ادامه دارد.

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

شايد برنامه‌نويسي رويه‌اي (Procedural Programming) اولين پارادايم مطرح‌شده براي زبان‌هاي برنامه‌نويسي است. در اين پارادايم، اعمال، مرحله به مرحله توسط فراخواني رويه‌هايي كه براي انجام كارهاي مختلف نوشته مي‌شوند، انجام مي‌گيرند. اين مدل با مشخص كردن ترتيبي براي فراخواني رويه‌ها يكي‌يكي آن‌ها را اجرا مي‌كند و با اتمام كار هر كدام رويه بعدي اجرا مي‌شود.

در حقيقت، برنامه‌نويسي رويه‌اي، ادامه  ايده كلي‌تري  به‌نام برنامه‌نويسي امري (Imperative Programming)  است. به‌طور ساده استراتژي اين مدل برنامه‌نويسي به اين صورت است كه تعدادي دستور وجود دارند كه بايد توسط كامپيوتر اجرا شوند. زبان‌هاي امري دقيقاً مانند اسمشان عمل مي‌كنند: اول اين كار را انجام بده، بعد آن را و... .

برنامه‌نويسي شيءگرا نيز در بيشتر مواقع مثالي از مدل امري است، زيرا در آن‌جا نيز روش كار برنامه عموماً به صورت اجراي سلسله‌اي از دستورها است. اگرچه معمولاً برنامه‌نويسي شيءگرا به صورت يك مدل جداگانه مورد بررسي قرار مي‌گيرد.

در مقابل مدل برنامه‌نويسي امري، مدل اعلاني (Declarative) قرار دارد. در اين مدل تمركز روي ماهيت چيزها است نه نحوه كاركرد آن‌ها. در مدل اعلاني آن‌چه اهميت دارد، توصيف اين است كه يك جزء برنامه چگونه است، نه اين‌كه چگونه ساخته مي‌شود. اگر برنامه خود را به دو قسمت منطق و كنترل تقسيم كنيد، در مدل اعلاني شما منطق برنامه خود را در اختيار مي‌گيريد و نگران آن‌چه در بخش كنترل اتفاق مي‌افتد، نيستيد. مثال بارز اين‌گونه زبان‌ها، HTML است2.

با توجه به نزديك بودن ساختار مدل اعلاني به ساختار رياضيات، اثبات درستي يك برنامه در اين مدل راحت‌تر انجام مي‌گيرد. به همين دليل، مدل اعلاني در نوشتن برنامه‌هايي كه بايد درستي آن‌ها به صورت يك حكم رياضي ثابت شود، كاربرد فراواني دارد.

عموماً زبان‌هاي مدل امري در محيط‌هاي كاري از محبوبيت بيشتري برخوردارند، اما نمي‌توان از تأثير مدل اعلاني در ساخت برنامه‌هاي علمي (به خصوص رياضي) به سادگي گذشت.

اين معرفي بسيار كوتاه از پارادايم‌ها فقط براي اين بود كه بدانيم آن‌ها واقعاً يكي نيستند! هر پارادايم، يك سبك برنامه‌نويسي و از آن مهم‌تر يك سبك نگرش را به دنبال دارد كه مي‌تواند تعاريف و اصول يك برنامه‌نويس را دگرگون سازد. پارادايم‌ها قطعاً به وجود نيامده‌اند كه معجزه كنند، بلكه قرار است كار را براي برنامه‌نويسان راحت‌تر سازند.

Aspect-Oriented Programming نيز، كه در واقع در ادامه مدل OOP عرضه شد، يك پارادايم برنامه‌نويسي است كه در ادامه به معرفي آن مي‌پردازيم.


وقتي OOP جواب‌گو نيست‌...
سناريوي زير را در نظر بگيريد:
فرض كنيد شما مسئول طراحي وب‌سايت براي يك شركت فروش آنلاين لباس شده‌ايد. اين سايت، مانند بيشتر سايت‌هاي دنيا دو بخش دارد: بخش نخست براي مشتريان كه مي‌توانند در آن اجناس را مشاهده كنند و آن‌ها را بخرند. بخش دوم نيز براي انجام كارهاي اداري خود شركت است كه فقط كارمندان خاصي به آن دسترسي دارند.

به‌عنوان مثال، اضافه كردن اقلامي به فروشگاه آنلاين يا بررسي كردن حساب بعضي از مشتري‌ها. شما و گروه برنامه‌نويسي با تلاشي قابل ستايش سايتي بسيار جامع و زيبا طراحي مي‌كنيد و آن را به شركت ارائه مي‌دهيد. اما روزي كه براي دريافت حق‌الزحمه خود مي‌رويد، متوجه مي‌شويد كه همه از دست شما عصباني هستند.

كارمندان نمي‌توانند البسه جديد را وارد فهرست فروشگاه كنند، كاربران سايت در حال افزايش اعتبار حساب كاربري خود به صورت دستي هستند! ايميل كاربران با فرمت اشتباه ذخيره شده است، پيگيري فروش روز‌هاي قبل در مواردي دچار مشكل مي‌شود و... . مشكل چيست؟

با افزايش پيچيدگي در يك برنامه نحوه كنترل شما روي روند رشد آن نيز دشوارتر مي‌شود. با اين كه ممكن است در بسياري از قسمت‌هاي برنامه كارهايي شبيه به هم انجام دهيد، اما جا انداختن يكي از اين كارها در هر يك از قسمت‌ها مي‌تواند كارايي كل برنامه شما را زير سؤال ببرد.

به مثال امنيت سايت فروش لباس باز مي‌گرديم. شما متوجه مي‌شويد با توجه به پيچيده شدن معماري سايت، بسياري از كارهاي ضروري را از قلم انداخته‌ايد.

در بسياري از جاها فراموش شده كه قبل از فراخواني روش‌هاي امن (Secure) هويت كاربر مشخص شود تا فرد غيرمسئول نتواند به اطلاعات محرمانه دسترسي داشته باشد. در بسياري از قسمت‌ها ورودي‌هاي اشتباهي كه كاربران به صورت دستي به سيستم مي‌دهند، تأييد اعتبار (Validate) نمي‌شوند و اين باعث بروز سردرگمي در سيستم مي‌شود.

در ضمن در بعضي از روش‌ها با توجه به زياد بودن كارهاي حاشيه‌اي (مانند ثبت كردن عمليات يك سيستم (Logging)، تراكنش‌هاي پايگاه‌داده و مديريت خطاها فراخواني روش‌هاي بعضي كارها از قلم افتاده‌است. در نتيجه سايت كاملاً كارايي خود را از دست داده و عملاً به يك سيستم خراب تبديل شده‌است.

از تمام اين موارد بدتر اين‌كه مشكلات شما به اينجا ختم نمي‌شود. وقتي درصدد اصلاح كدها بربياييد، مي‌بينيد اين‌كار خيلي دشوارتر از آن است كه تصور مي‌كرديد، زيرا كد هر قسمت آميخته‌اي از روند كاري اصلي برنامه (Business Logic) و كارهاي حاشيه‌اي مانند بررسي كردن امنيت و Logging و ... است.

جداسازي كد به صورتي كه بتوانيم بخش‌هاي مختلف را مورد بررسي قرار دهيم، كار بسيار مشكلي است و اين‌كار شما و گروه طراحي را دشوارتر از قبل مي‌كند.

مشكل سايت قسمت بالا مشكل تمام سيستم‌هاي شيءگرا است. به كارهاي مذكور كه براي تمام قسمت‌هاي سايت يكسان هستند، Cross-Cutting Concern گفته مي‌شود. در حقيقت، Cross-Cutting Concern ،Concernهايي هستند كه در چندين قسمت سيستم مورد توجه قرار مي‌گيرند (به‌عنوان نمونه، در مثال بالا بررسي امنيت و تراكنش‌هاي پايگاه‌داده و عمليات Logging).

اين Concernها معمولاً نمي‌توانند در يك ماجول به‌طور كامل  كپسوله شوند. همان‌طور كه در مثال مذكور مي‌بينيد، بايد چندين فراخواني هر كدام از آن‌ها را در سيستم‌هاي امنيتي بالا قرار دهيم تا بتوانند آن‌ها را به قسمت برقراري امنيت متصل كنند. Cross-Cutting Concern جايي است كه ديگر مدل شيءگرا جواب كارآمدي به ما نمي‌دهد.

AOP؛ تولد يك مفهوم‌
در 1997 گريگور كيزالس و گروهش در زيراكس پارك مفهومي را معرفي كردند كه Aspect Oriented Programming يا به اختصار AOP ناميده مي‌شود. نام اوليه اين پروژه تجزيه و سرهم كردن (Decomposition & Weaving) بود، اما بعدها به AOP تغيير نام داد.

كيزالس درباره اين موضوع مي‌گويد: «اين نظر يكي از اعضاي گروه بود كه به درستي اشاره كرد تلفظ اين نام بسيار سخت است و در ضمن به نظر كمي زيادي 3Nerdy است.»

AOP، در حقيقت به‌عنوان يك مكمل براي برنامه‌نويسي شيءگرا عرضه شد تا ضعف‌هايي را كه در قسمت قبل به اختصار به آن اشاره كرديم پوشش دهد. كار اصلي AOP كار كردن با Cross-Cutting Concernها است. اما بياييد دقيق‌تر به مفهوم AOP بپردازيم.

 شما براي نوشتن يك برنامه علاوه بر منطق كاري برنامه خود (كه جريان اصلي برنامه است)، بايد به‌طور هم‌زمان نگران بسياري از كارهاي حاشيه‌اي ديگر نيز باشيد. سؤال‌هايي از قبيل: «اگر يك قسمت از برنامه مطابق پيش‌بيني كار نكرد، چه كنم؟» يا «چگونه امنيت را به برنامه‌ام تزريق كنم؟» يا حتي «چگونه مديريت حافظه را انجام دهم؟»، سؤالاتي هستند كه هر برنامه‌نويس در طول يك پروژه بارها از خود مي‌پرسد. اما چگونه بايد با اين Concernها كنار آمد؟

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

البته انجام كارهاي حاشيه‌اي در پشت صحنه ايده‌اي قديمي‌تر از AOP است. به‌عنوان مثال، مي‌توانيد انجام مديريت حافظه و Garbage Collection توسط JVM در زبان جاوا را در نظر بگيريد. شما مي‌توانيد كد خود را بدون نگراني درباره مسائل مربوط به دو مورد ذكرشده در بالا بنويسيد، زيرا جاوا خود با آن‌ها كنار مي‌آيد.

انجام جداگانه كد و كارها باعث افزايش modularization مي‌شود و همه برنامه‌نويسان مي‌دانند كه اين افزايش مي‌تواند چه‌قدر دنيا را زيبا كند!

جان هانت مي‌گويد: «من هنوز مي‌توانم خودم را جلوي سورس كد يك برنامه تصور كنم در حالي‌كه سعي مي‌كنم منطق كاري پايه‌اي آن را از بقيه چيزهاي دور و برش مجزا سازم.» شايد شما هم در غم  او شريك باشيد. درك سازوكار اصلي كاركرد يك برنامه، موضوع بسيار مهمي است كه معمولاً بسيار سخت انجام مي‌گيرد.

زيرا تمام كد اصلي برنامه با جزئيات حاشيه‌اي (البته نه لزوماً از نوع پيش‌پا افتاده) مخلوط شده‌است كه علاوه بر مشغول ساختن ذهن كدنويس و كند كردن فرآيند عيب‌يابي، باعث مي‌شود تا درك روند كاري اصلي كد نيز براي كسي كه سعي در فهم آن دارد، بسيار مشكل شود.

اما راه حل گروه كيزالس براي اين موضوع چه بود؟ چيزي كه آن‌ها عرضه كردند مي‌توانست Cross-Cutting Concernها را به صورت يك ماجول جداگانه مورد بحث قرار دهد. ماجولي كه علاوه بر عمليات اصلي كه بايد انجام دهد، در برگيرنده شرط اجراي اين Concernها نيز است.

بگذاريد با ذكر يك مثال موضوع را مشخص كنيم. به همان بحث امنيت باز مي‌گرديم. در مدل شيء‌گرا راه‌حل ما ساختن يك كلاس (يا يك روش در يك كلاس) براي بررسي بحث دسترسي كاربر موردنظر بود. پس از ساخت يك ماجول براي بررسي، با اضافه كردن عبارت‌هاي فراخواني آن در قسمت‌هاي مختلف برنامه، كار را تكميل مي‌كنيم.

در حقيقت، روند كاري در مدل شيء‌گرا در دو جا دنبال مي‌شود. يكي كلاس يا روشي كه براي بحث امنيت نوشته‌ايم،‌ يكي هم مكان‌هاي فراخواني آن از كد اصلي برنامه.

اما راه‌حل AOP متفاوت است. در AOP دو مكان قبلي (ماجول امنيت و مكان فراخواني) تقريباً با يكديگر تركيب مي‌شوند. به اين ترتيب كه شما كد مربوط به Concern (در مثال ما چك كردن امنيت) را در يك ماجول جداگانه قرار مي‌دهيد و سپس در همان ماجول شرط‌هاي فراخواني اين كد را ذكر مي‌كنيد (به‌عنوان مثال، درباره بحث موردنظر ما بايد بررسي هويت در مواردي انجام شود كه يك روش امن فراخواني مي‌شود).

به اين ترتيب، تمام روند كاري Cross-cutting Concernها از سازوكار اصلي برنامه مجزا مي‌شوند. كاملاً مشخص است كه اين جدايي مي‌تواند چه مزيت‌هايي را براي سيستم به ارمغان بياورد. به‌عنوان مثال، مي‌توان اين دو بخش كد (كد اصلي و Cross-cutting Concernها) را به دو گروه مختلف برنامه‌نويسي واگذار كرد يا حتي درباره خود Cross-cutting Concernها مي‌توان هر بخش را به خبره  آن كار سپرد. مثلاً بخش بررسي كردن امنيت به متخصصان امنيت يا بخش تراكنش‌هاي پايگاه‌داده به متخصصان آن.

شايد باز هم اصرار كنيد كه تمام اين كارها با مدل شيءگرا نيز قابل دسترس بود (بحث كامل‌تري درباره اين مقايسه در بخش آخر مقاله آمده است). البته درست مي‌گوييد! اما توجه داشته باشيد كه در يك مدل شيء‌گرا برنامه‌نويس بايد از نكات زير آگاهي داشته باشد:

1- برنامه‌نويس بايد از وجود چنين كلاس‌هايي كه براي هماهنگ كردن اين Cross-cutting Concernها ساخته شده است، خبر داشته باشد.

2- بايد Specification دقيق آن كلاس را بداند تا بتواند از آن استفاده كند.

3- بايد بداند دستور مربوط به فراخواني روش‌هاي آن كلاس را كجاي كد اصلي قرار دهد.

در تمام اين سه مرحله امكان رخ دادن خطا وجود دارد. به خصوص در قسمت آخر كه فراموشي برنامه‌نويس براي فراخواني تمام روش‌هاي لازم از شايع ترين اشتباه‌ها است. اما با استفاده از AOP، با توجه به جدا شدن دغدغه‌هاي برنامه‌نويسان اين دو بخش چنين مشكلاتي اصولاً مطرح نمي‌شوند (البته مشكلات ديگري مطرح مي‌شوند كه چند نمونه از آن‌ها در قسمت آخر مقاله مطرح مي‌شود).

با استفاده از AOP مي‌توانيم بدون تغيير كد اصلي، Concernهايي به آن اضافه كنيم كه رفتارهاي سيستم را تقويت كند. در بخش بعد به بررسي مفاهيم اصلي AOP مي‌پردازيم.

اين يك AOP است...
چه چيزي مُهر AOP را روي يك سيستم مي‌زند؟ مسلماً معيار طراحي يك سيستم براساس AOP، اين نيست كه سازنده آن اين‌گونه بگويد.

اين موضوع كه آيا يك پروژه از AOP استفاده مي‌كند يا خير، به مكانيزم كاري آن پروژه و ماهيت نيازهاي آن بستگي دارد. به‌عنوان مثال، كل عمليات مربوط به پرينت كردن يك سند را در نظر بگيريد. شما ممكن است در قسمت‌هاي مختلفي از برنامه خود عمليات پرينت كردن را نياز داشته باشيد. به اين ترتيب، بايد بارها روش‌هاي مربوط به آن را فراخواني كنيد. ممكن است با توجه به اين تعاريف شما پرينت را به صورت يك Concern در نظر بگيريد. اما آيا اين طراحي يك طراحي منطقي است؟

در تعريف Concernهايي كه در AOP مورد توجه قرار مي‌گيرند يك نكته فرعي وجود دارد و آن اين است: اين Concernها معمولاً به صورت يك ماجول جداگانه (در مدل هاي قبل از AOP) دسته‌بندي نمي‌شوند. اين تعريف جواب سؤال بالا را مشخص مي‌كند.

در مثال بالا روش‌هاي مربوط به عمليات پرينت كردن براي برنامه‌نويس كاملاً مشخص است و مطرح كردن اين نكته كه او ممكن است فراموش كند كه آن‌ها را فراخواني كند تا حدودي خنده‌دار به نظر مي‌آيد. پس چندان منطقي نيست كه پرينت كردن را به وسيله AOP پياده‌سازي كنيم.

عدم استفاده از AOP در مثال بالا بديهي بود، اما ايده پشت اين مطلب را مشخص مي‌كند. AOP بايد در مواردي به كار گرفته شود كه به آن نياز است. وقتي مكانيزمي كه وجود AOP را مي‌طلبد، موجود نيست مي‌توانيم خيلي راحت از پارادايم هاي ديگر استفاده كنيم. پس بايد قبل از استفاده از AOP نيازهاي يك سيستم را كاملاً تحليل كنيم تا لزوم يا عدم لزوم به كارگيري آن را مشخص سازيم.

در ادبيات AOP، تعاريفي رسمي‌تر از مفاهيم اوليه آن وجود دارد كه موارد استفاده AOP را روشن‌تر مي‌كند.

Quantification يا تعيين عناصر

Quantification ايده‌اي است كه در آن يك برنامه‌نويس مي‌تواند با نوشتن يك سري عبارت در قالب يك واحد و به صورت مجزا از بقيه سيستم، بسياري از جاهاي غيرمحلي برنامه را تحت‌تأثير قرار دهد. درباره AspectهاQuantification مي‌تواند به اين صورت معني شود كه توانايي Aspectها براي اثرگذاري در نقاط مختلف يك برنامه است.


Obliviousness يا فراموش‌كاري‌
Obliviousness بيانگر اين ايده است كه يك برنامه اطلاعي از اين كه يك Aspect كي و كجا اجرا مي‌شود، ندارد. نتيجه اين‌كه شما نمي‌توانيد با نگاه كردن به كد بگوييد كدام Aspect اجرا مي‌شود و اين باعث ارتقاي مفهوم جدا‌سازي مي‌شود.


تعريف Filman-Friedman
دو مفهوم ذكر شده در بالا (تعيين عناصر و فراموش‌كاري) از ديدگاه تعريف Filman-Friedman دو مفهوم لازم‌الاجرا در زمينه طراحي برنامه‌هاي Aspect Oriented هستند. در حقيقت، با توجه به اين تعريف هر طراحي بايد شامل هر دو ايده به‌طور كامل باشد.

هرچند خيلي‌ها اين دو تعريف را بسيار سخت‌گيرانه مي‌دانند، زيرا برنامه‌هاي بسياري با طراحي AOP وجود دارند كه تنها به خاطر جلوگيري از اختلا‌ط دو كد، يكي از آن‌ها Aspect محسوب مي‌شود كه اين طراحي لزوماً نقاط مختلف برنامه را مورد هدف قرار نمي‌دهد (مثال رعايت نشدن تعيين عناصر). همچنين در بعضي مواقع، برنامه‌نويسان AOP محل فراخواني Aspect را با علا‌متي خاص مشخص مي‌سازند (مثال رعايت نشدن فراموشكاري)


دو اصطلاح Tangling و Scattering
‌ پراكندگي: (Scattering) پياده‌سازي يك Concern، پراكنده شده است هر گاه كد آن بين چند ماجول پخش شده باشد.
پيچش: (Tangling) پياده‌سازي يك Concern، پيچيده شده‌است هر گاه كد آن با كد يك Concern ديگر مخلوط شده باشد.

پراكندگي و پيچش در Aspect Oriented به‌عنوان علائم يك Cross-Cutting Concern در نظر گرفته مي‌شوند. در حقيقت عموماً Concernهايي كه چنين خصوصياتي را در پياده‌سازي‌هاي غير AOP داشته باشند، مورد بحث قرار مي‌گيرند.

AOP در عمل‌
بايد اعتراف كرد كه با وجود ارزشمند بودن توضيحات و تئوري‌هاي برنامه‌نويسي، تا وقتي كه آن‌ها را در عمل، به وسيله برنامه‌نويسي مورد آزمايش قرار ندهيم، در حقيقت كار خاصي انجام نداده‌ايم. در ادامه سعي مي‌كنيم مفاهيم مطرح شده را به همراه كد آن مورد بررسي قرار دهيم تا علاوه بر معرفي و تعريف مفاهيم موجود در AOP، با نحوه به كارگيري آنان نيز آشنا شويم، اما قبل از هر چيز بايد به اين سؤال پاسخ دهيم كه كجا مي‌توانيم AOPبنويسيم؟

براي پاسخ دادن به اين پرسش، ابتدا بايد ببينيد AOP چگونه اجرا مي‌شود. براي نوشتن يك پروژه به صورت AOPشما ابتدا هر دو بخش كد خود را (اعم از روند كاري اصلي برنامه و كدهاي مربوط به Aspectها) به صورت جداگانه در يك زبان شيءگرا مي‌نويسيد و سپس موجودي به نام Aspect Weaver آن دو بخش را با يكديگر تركيب كرده و كد نهايي را مي‌سازد.

جداسازي كد اصلي و كد Concernها (كد اصلي نيازي به اطلاع از بخش Concernها ندارد) به افزايش قابليت استفاده دوباره‌ (Reusability) و قابليت نگهداري (Maintainability) پروژه كمك شاياني مي‌كند. شكل 1 نحوه كار Weaverها را نشان مي‌دهد.

دو نمونه بارز از ابزارهايي كه مي‌توان با استفاده از آن‌ها برنامه‌هاي Aspect-Oriented نوشت AspectJ و AspectWerkz هستند.

AspectJ يك Extension است كه براي زبان جاوا در زيراكس پارك و توسط گروه به‌وجود آورنده AOP نوشته شده‌است. اين Extension به دو صورت تنها و تعبيه شده در Eclipse IDE عرضه مي‌شود. AspectJ پتانسيل پشتيباني از مدلRT Weaver را نيزدارد، اما براي بهره بردن از توانايي‌هاي آن بايد از آن به‌صورت يك Compile-time Weaver استفاده كرد (هم‌اكنون به صورت Compile-time و loadtime عرضه مي‌شود).

 

Aspect Weaver !

در حقيقت Aspect Weaver كد اصلي و كد Aspectها را به‌عنوان ورودي مي‌گيرد و محصول نهايي را توليد مي‌كند. توجه به اين موضوع ضروري است كه نگاه كلي به Weaverها مانند يك كامپايلر نيست، زيرا قرار نيست كه تمام كارهاي پيچيده‌اي را كه يك كامپايلر انجام مي‌دهد.

Weaver نيز در مورد تركيب دو بخش كد انجام دهد. در حقيقت، همان‌طور كه خود كيزالس هم اشاره مي كند، وظيفه Weaverها فقط Integration (مجتمع‌سازي) است.

تكنيك‌هاي اوليه Weaving به دو دسته عمده تقسيم مي‌شوند: Compile Time) CT) و Run-Time) RT Weaver)هايCT. همان‌طور كه از نامشان پيدا است، تمام كارهاي مربوط به تركيب كد را در زمان كامپايل انجام مي‌دهند و در حقيقت كد نهايي كه اجرا مي‌شود، محصول كامل است.
 
در مقابل RTها اين‌كار را در زمان اجرا انجام مي‌دهند و ايجاد ارتباط را تا آن وقت به تأخير مي‌اندازند. Weaverهاي CT با توجه به اين كه تمام فرآيند ايجاد ارتباط را در ابتداي كار و هنگام كامپايل انجام مي‌دهند بسيار سريع‌تر از RTها عمل مي‌كنند، اما در مقابل RTها هم اين مزيت را دارند كه در صورت تغيير كد Aspectها نيازي به انجام دوباره عمليات Weaving نيست و برخلاف CTها در Run-Time Weaver تغييرات در كد بدون نياز به هيچ كاري سريع منعكس مي‌شوند.

همان‌طور كه در بالا ذكر كرديم، تكنيك‌هاي Weaving ديگري نيز وجود دارند كه در واقع فضاي بين Compile-time و Run-time قرار مي‌گيرند. اين دو تكنيك Weaving را (post-compile time (binary و Load-time مي‌نامند.

Binary Weaving در حقيقت عمليات Weaving را روي byte code انجام مي‌دهد (پس از كامپايل). Load time Weaving نيز يك نوع binary Weaving است. با اين تفاوت كه عمليات Weaving را تا زماني كه يك كلاس به Class loader معرفي نشده است، به تأخير مي‌اندازد.
 
(اين توانايي مي‌تواند برخي از نقص‌هاي مدل Compile-time را برطرف كند، زيرا شما مي‌توانيد بدون كامپايل كردن دوباره كد اصلي خود (Aspect ،(Business Logicهايي به برنامه اضافه كرده و سپس آن‌ها را به پروژه  اصلي لينك دهيد). در حقيقت، در اين مدل تا جايي كه ممكن است عمليات Weaving به تأخير مي‌افتد و تا مرحله Load شدن كلاس‌هاي موردنياز هيچ تركيبي انجام نمي‌شود.

AspectJ محيطي ساده و بسيار كارا دارد و هم‌اكنون محبوب‌ترين ابزار برنامه‌نويسي Aspect-Oriented است. نسخه‌هاي جديدتر AspectJ به‌طور كامل با محيط توسعه Eclipse هماهنگي دارند و مي‌توان از تمام امكانات Eclipse در مورد Aspect‌ها نيز سود برد.

توجه به اين نكته ضروري است كه AspectJ تغييراتي در Syntax زبان به وجود مي‌آورد كه اين موضوع مي‌تواند باعث بروز مشكلاتي شود (Eclipse با توجه به اضافه كردن Keywordهاي مربوط به برنامه‌نويسي AOP اين مشكل را ندارد).

اين مشكلات باعث شدند تا ابزارهاي ديگري به وجود آيند كه به اين تغييرات گرامري در زبان برنامه‌نويسي نيازي نداشته باشند. يك نمونه مشهور از اين زبان‌ها‌ AspectWerkz است. AspectWerkz در حال حاضر از هر سه مدل Compile-time ،Load-time و Run time استفاده مي‌كند.

خصوصيت بارز AspectWerkz اين است كه Syntax زبان را تغيير نمي‌دهد و در حقيقت تغييرات را با استفاده از Annotation انجام مي‌دهد كه به يك ساختار زباني جديد نيازي ندارد.

در حال حاضر، دو پروژه AspectJ و  AspectWerkz با يكديگر تركيب شده‌اند تا بتوانيم از قابليت‌هاي هر دو به صورت هم‌زمان استفاده كنيم.

تمام اين مقدمه‌ها براي اين ذكر شد كه شما كمي بيشتر با نحوه عملكرد داخلي ابزارهاي توسعه برنامه‌هاي Aspect-Oriented آشنا شويد. در قسمت بعد وارد بخش كدنويسي مي‌شويم.

كدنويسي در AspectJ




 Annotation

 شايد تعريف كردن Annotation كمي دشوار باشد. در حقيقت آن‌ها برچسب‌ها و شايد پايگاه‌داده‌هايي هستند كه اطلاعاتي درباره برنامه شما مي‌دهند.

در حقيقت، Annotationها تغييري در Semantic زبان ايجاد نمي‌كنند، اما مي‌توانند براي ابزارهاي مختلفي كه در روند اجراي برنامه دخيل هستند، پيغام‌هايي در برداشته باشند.

در حقيقت، مي‌توان Annotationها را علامت‌هايي تلقي كرد كه كامپايلر آن‌ها را به‌عنوان متاديتا در جايي ذخيره مي‌كند. سپس VM (سرنام Virtual Machine) با ديدن آن‌ها تعيين مي‌كند كه چگونه رفتار بعضي از Elementهاي برنامه را تغيير دهد.

توضيح كامل Annotationها در اين مقاله نمي‌گنجد. پس به ذكر همين مقدمات بسنده مي‌كنيم.

در اين قسمت به بررسي پياده‌سازي مفاهيم مختلف AOP توسط AspectJ مي‌پردازيم. هر چند بررسي تمام خصوصيات AspectJ خود يك مقاله جداگانه مي‌طلبد، اما سعي مي‌كنيم تا مفاهيم اصلي پركاربرد را در نوشتن يك برنامه Aspect-Oriented مطرح كنيم. در شماره‌هاي آينده، به‌طور عميق‌تري به بررسي جنبه‌هاي عملي AOPمي‌پردازيم.

 

Join Point
Join Point، در حقيقت مفهوم جديدي نيست. ما از اين مفهوم قبلاً بارها استفاده كرده‌ايم ، فقط شايد اسمي براي آن نداشته‌ايمJoint Point .ها نقاط خوش تعريف خاصي در برنامه هستند. به‌عنوان مثال، نقطه فراخواني يا بازگشت متد.

Aspect
شروع كاري ما براي آوردن AOP به صحنه عمل كليدواژه Aspect است. Aspectها تقريباً مشابه كليدواژه class در نوشتن كدهاي معمولي شيءگرا هستند. هر Aspect بايد در يك فايل جداگانه كه نام آن با نام Aspect يكي است، تعريف شود:
 

يك Aspect مجموعه‌اي از point-cutها و Adviceها است.


Point-cut
در AOP شما نياز داريد نقاط خاصي را به‌عنوان نقاطي كه موجب فراخواني يك Aspect مي‌شوند، تعريف كنيد. اين كار توسط Point-cutها انجام مي‌گيرد. در حقيقت، Point-cutها يك مجموعه از Join Pointها را تعريف مي‌كنند و مي‌توانيم آن‌ها را به‌عنوان يك Query براي انتخاب joint pointها در نظر بگيريم.

 
در حقيقت، تعريف يك point-cut بيان‌كننده اين موضوع است كه join Pointهاي كد اصلي (Business Logic) در چه جاهايي قرار دارند. به زبان ساده‌تر point-cut شرايط نقطه‌هايي را تعريف مي‌كند كه بايد با رسيدن به آن‌ها در كد اصلي اين Aspect اجرا شود.

اين مكانيسم، به مكانيسم فراخواني روش بسيار شبيه است. در حقيقت، در اينجا point-cutها حكم يك روش و join point حكم نقطه‌اي است كه دستور فراخواني متد در آن قرار دارد.

به عنوان مثال:

اين Pointcut مشخص مي‌كند كه پس از اجراي متد از كلاس Data كه با Write شروع مي‌شوند و هيچ ورودي‌اي ندارند، اين Aspect فراخواني مي‌شود.
‌مي‌توانيم در يك Aspect چند pointcut داشته باشيم.  كد پايين سه pointcut تعريف مي‌كند.




در كد بالا سه pointcut تعريف شده است.

PC1: وقتي متدي از كلاس Data كه با Write شروع مي‌شود و آرگومان String مي‌گيرد، فراخواني مي‌شود، pointcut PC1 رخ مي‌دهد.
PC2: با فراخواني هر متدي (هر نامي با هر ورودي‌اي) كه در داخل كلاس Data است pointcut PC2 رخ مي‌دهد.
PC3: با اجراي بدنه اصلي متد SecurityChecking ،pointcut PC3 فراخواني مي‌شود.


Advice
كد تكميلي كه به سيستم اضافه مي‌شود تا كارهاي مربوط به يك Concern را انجام دهد، Advice نام دارد. Adviceها در حقيقت همان قطعه‌كدهاي معمولي هستند كه حكم انجام عملياتي يك Concern را دارند. 
هر Advice كاري را كه يك Aspect بايد در ازاي وقوع يك اتفاق خاص (pointcut) انجام دهد، مشخص مي كند. باز هم با تعبير متدگونه advice در واقع حكم بدنه متد را دارد (point-cut حكم اعلان متد را دارد).
 
كاري كه كد زير انجام مي‌دهد اين است كه قبل از اجراي هر متدي از كلاس Data كه با Write شروع مي‌شود و هيچ ورودي ندارد، هويت كاربر حال حاضر بررسي مي‌شود.



Adviceها به سه نوع تقسيم مي‌شوند:

1-Before: اين Adviceها بلافاصله بعد از اين‌كه يك join point اتفاق افتاد و پيش از اين كه برنامه ادامه يابد اجرا مي‌شوند. به‌عنوان مثال، اگر join point فراخواني يك ljn باشد، بلافاصله پس از فراخواني ljn (و پيش از اجراي بدنه آن و برگرداندن يك مقدار)، قطعه كد Advice اجرا مي‌شود.

2- After: اين نوع Advice نيز همان‌طور كه از نامش پيدا است، درست برخلاف Before عمل مي‌كند. Adviceهاي نوع After پس از پايان اجراي join point، اجرا مي‌شوند. در حقيقت، در مثال بالا (فراخواني متد) يك Advice از اين دسته پس از پايان روند كاري متد (برگرداندن مقدار- وقوع exception) اجرا مي‌شود.

3- Around: اين نوع بسيار جالب از Adviceها مي‌توانند كلاً اجراي join point را ناديده بگيرند. در حقيقت Adviceهاي نوع Around دقيقاً به جاي join point اجرا مي‌شوند (اجراي join point ناديده گرفته مي‌شود و به جاي آن اين Advice اجرا مي‌شود). معني اين امر درباره متدها اين است كه بدنه  اصلي متد اجرا نمي‌شود و به جاي آن كد موجود در Advice اجرا مي‌شود.

يك كد تركيبي‌
كد زير تركيبي از سه pointcut و سه Advice را نشان مي‌دهد.



كد زير نيز كد كلاس Data است كه شامل روش main نيز است.



پس از كامپايل و اجراي Data خروجي زير را دريافت مي‌كنيم:



 به ترتيب خروجي‌ها دقت كنيد. در PC1 نحوه مشخص كردن آرگومان ورودي متد و استفاده از آن را مشاهده مي‌كنيد. در PC2 مطابق تعريف تمام پيغام‌هاي Logging همان‌طور كه در كد pcAspect2 تعريف شده بود، بعد از اجراي تمام متدها چاپ شده است.

در PC3 نحوه استفاده از شيء كلاس مبدأ را مشاهده مي‌كنيد. در ضمن كد متد SecurityChecking در كلاس Dataاصلاً اجرا نشده است، زيرا ما Advice‌اي را كه بايد درباره اين متد اجرا مي‌شد، around در نظر گرفته‌ايم و همان‌طور كه در بالا ذكر شد Adviceهاي نوع around كلاً اجراي عادي join point را متوقف مي‌كنند.

احتمالاً با بررسي اين كد، متد كار Adviceها و point-cutها تا حدود زيادي براي شما روشن شده‌است. البته پياده‌سازي‌هاي اين مفهوم ريزه‌كاري‌هاي بسيار پيچيده‌تري نيز دارند كه در اين مقاله نمي‌گنجد.


Inter-type Declaration
Inter-type Declaration امكان جالبي است كه به برنامه‌نويس اجازه مي‌دهد ساختار elementهاي برنامه را در صورت اجرا شدن يك Aspect تغيير دهد، اما تغيير ساختار به چه معنا است؟

- اضافه كردن متد، Constructor يا Field به ديگر Typeهاي برنامه (كلاس يا Aspectهاي ديگر)
- اضافه كردن يا تغيير اينترفيس‌ها و كلاس‌هاي والد تعيين شده براي Typeهاي ديگر
- تغيير حالت exceptionها از checked به unchecked
- ‌اضافه كردن warningهاي دلخواه و... .

در حقيقت، با استفاده از اين توانايي يك Aspect مي‌تواند به‌طور كامل وظيفه تعريف، نگهداري و اجراي elementهاي مورد استفاده خود را بر عهده بگيرد و اين موضوع باعث مي‌شود تا تمام موضوعات مربوط به Aspectنويس در همان فايل aspect خلاصه شود.

نوشتن كدي كه از Inter-type Declaration عموماً چيز جديدي در بر ندارد و در بيشتر موارد مانند روش كلاسيك كد نوشتن ما است. به‌عنوان مثال، كد زير به ترتيب يك Field و يك متد براي كلاس AirPlane تعريف مي‌كند.



قطعه كد زير نيز يك‌ Constructor دو Argumentي براي كلاس AirPlane تعريف مي‌كند.



كد زير نيز كلاس والد كلاس AirPlane را كلاس  SomethingFly تعيين مي‌كند.



چگونه اين‌ها را اجرا كنيم؟

اجراي يك برنامه نوشته شده تحت AOP در AspectJ با اجراي يك برنامه معمولي جاوا چندان تفاوتي ندارد. ابتدا نحوه اجراي يك برنامه را كه براي Weaving از تكنيك Compile-time استفاده مي‌كند، نشان مي‌دهيم.

به‌طور كلي براي كامپايل كردن اين برنامه‌ها، AspectJ دستور ajc را در نظر گرفته است. ساده‌ترين نوع كامپايل به صورت زير است.




براي اجراي برنامه نيز نبايد مشكلي داشته باشيم. زيرا تركيب ‌(Weaving) بين Aspect و كد اصلي انجام شده است و ما هم‌اكنون يك فايل class. كامل در اختيار داريم. پس مي‌توانيم به سادگي آن را اجرا كنيم.



مدل Load-time
اكنون سعي مي كنيم با ذكر يك مثال، نحوه  اجراي يك برنامه به صورت Load-time و اثرات آن را مشاهده كنيم.
كد ارائه‌شده در بخش <يك كد تركيبي> در قسمت قبل را در نظر بگيريد. فرض كنيد مي‌خواهيم يك Aspect ديگر به نام «pcAspect3» داشته‌‌باشيم. «pcAspect3.java» به صورت زير در نظر گرفته مي‌شود:




براي اضافه كردن aspect2 به پروژه مي‌توان دو كار انجام داد:

1- مانند قبل عمل مي‌كنيم و سه فايل data و pcAspect2 و pcAspect3 را با يكديگر كامپايل مي‌كنيم. عمليات Weaving به صورت Compile-time انجام مي‌شود و با اجراي كلاس Data نتيجه موردنظر را دريافت مي‌كنيم.

2- از ‌load-time Weaving استفاده كنيم (براي تعريف load-time Weaving به كادر Aspect Weaver مراجعه كنيد).

اصولاً در بعضي موارد ممكن است كامپايل كردن دوباره تمام پروژه بسيار هزينه‌بر باشد. با استفاده از load-time weaving نيازي به كامپايل كردن دوباره هيچ‌كدام از فايل‌هاي قبلي نيست. بلكه ما فقط كلاس فايل جديدمان را به بقيه فايل‌ها اضافه مي‌كنيم، سپس با اجراي دوباره پروژه تمام تغييرات لازم خود به خود، اعمال مي‌شود.

اما انجام اين كار به چه شكل است؟

همان‌طور كه ذكر شد ما بايد به نحوي بعد از كامپايل فايل اصلي يك Aspect را به آن معرفي كنيم.
اين اعلام به وسيله META-INF/aop.xml (فايل aop.xml درون دايركتوري META-INF) انجام مي‌گيرد. فايل aop.xml  مي‌تواند به روش‌هاي مختلفي ايجاد شود. استفاده از دستور زير به هنگام كامپايل فايل اوليه يك زير دايركتوري در دايركتوري فعلي، META-INF/aop.xml را ايجاد مي‌كند.




اين كار (ساخت فايل aop.xml) به صورت دستي نيز مي‌تواند انجام شود. اكنون بايد كد جديد خود را به قسمت اصلي برنامه اضافه كنيم. براي اين كار ابتدا كد جديد را به همان روش هميشگي كامپايل مي‌كنيم.



اعلان Aspectها در فايل aop.xml بسيار ساده است. فقط كافي است aop.xml را به صورت زير اصلاح كنيم.



اكنون با اجراي Data هر دو Aspect در پروژه اثر مي‌كنند. توجه كنيد كه در اينجا ديگر نمي‌توانيد از جاوا براي اجراي Data استفاده كنيد، زيرا در اينجا عمليات Weaving در هنگام Load شدن كلاس‌ها و بعد از اجرا انجام مي‌شود. پس بايد از دستور مخصوص اجرا به‌صورت Load-time Weaving استفاده كنيد.

اين دستور aj5) aj براي Java5) است.






و اما بعد...
اما سرنوشت AOP به كجا مي‌انجامد؟ در طول ساليان اخير ايده‌هاي مختلفي براي ايجاد يك پارادايم برتر ارائه شده‌است، اما همچنان مدل شيءگرا، به‌عنوان يك 4Silver Bullet براي عرصه پارادايم‌ها باقي مانده و سال‌ها است كه محبوب‌ترين شيوه توليد نرم‌افزار است.

AOP در تقابل با برنامه‌نويسي شيءگرا قرار نمي‌گيرد، اما همچنان عده‌اي با ترديد به توليد كيزالس و گروهش مي‌نگرند و استفاده از آن در مقياس وسيع را نيازمند تحقيق و بررسي بيشتري مي‌دانند. در اين ميان، عده‌اي پا را از اين نيز فراتر مي‌گذارند و AOP را ايده‌اي ناكارآمد در عمل و غيرقابل استفاده براي پروژه‌هاي بزرگ مي‌نامند. البته در مقابل اين دسته، افرادي نيز وجود دارند كه AOP را انقلابي در زمينه پارادايم‌هاي برنامه‌نويسي معرفي و استفاده از آن را به شدت پيشنهاد مي‌كنند.5

اما از اين افراطي‌گري‌ها چيزي نصيب مهندسان نرم‌افزار نمي‌شود. هر نظري كه درباره AOP داشته باشيد، خواه طرفدار پر و پا قرص، خواه مخالف شديد يا يك آدم بي‌طرف، در تمام موارد چيزي كه وجود دارد اين است: AOP فقط يك پارادايم برنامه‌نويسي است.

قرار نيست با AOP مشكلاتي را حل كنيد كه قبلاً نمي‌توانستيد آن را حل كنيد يا به بيان ديگر قرار نيست اين پارادايم براي شما نرم‌افزارهايي بسازد كه قبلاً نمي‌توانستيد آن‌ها را بسازيد.

رايان گالبِك درباره اين موضوع مي‌گويد: «مطرح كردن اين واقعيت كه شما مي‌توانيد همچنان با OOP سر كنيد و Cross-Cutting Concernها را با آن پياده‌سازي كنيد، چيزي را عوض نمي‌كند. زيرا بر اساس تز چرچ/تورينگ6 شما مي‌توانيد تمام مباحث موجود در مدل شيءگرا را در قالب زبان‌هاي رويه‌اي يا حتي كد اسمبلي پياده‌سازي كنيد. توانايي اصلي‌اي كه AOP براي شما به ارمغان مي‌آورد Modularization بهتر است نه قدرت بيشتر!»

صحبت‌هاي گالبِك را مي‌توان به تمام پارادايم‌هاي برنامه‌نويسي تعميم داد. پارادايم‌هاي برنامه‌نويسي براي ما ناممكن را ممكن نمي‌كنند (يا برعكس). بلكه فقط كمك مي‌كنند تا هزينه توليد و نگهداري يك پروژه براي شما كاهش يابد.

جدا از تمام اين‌ها، بحث‌هاي انتقادي اصولي نيز درباره AOP و نحوه Modularization آن وجود دارد كه قابل تعمق است. اصولا ًدر يك سيستم AOP-based به يك برنامه‌نويس قدرت بسياري داده مي‌شود كه اين موضوع مي‌تواند علاوه بر اثرات مفيد، مشكلاتي را نيز براي سيستم ايجاد كند.
 
توانايي ايجاد تغييرات كلي در سيستم توسط برنامه‌نويسي كه مسئوليت نوشتن كدهاي مربوط به يك Aspect را برعهده دارد مي‌تواند اثرات زيان‌باري روي كارايي كل سيستم شما بگذارد. Andres Hejlsberg معمار زبان #‌C، با وجود اين كه ايده AOP را ايده‌اي قابل تقدير و مستعد بررسي و تحقيق بيشتر مي‌داند، اما نگراني‌اش را از بابت قدرت زياد برنامه‌نويس، پنهان نمي‌كند:

«من هنوز نگراني‌هاي اساسي درباره Aspectهايي كه قدرت استدلال شما درباره كد خودتان را دچار مشكل مي‌كند، دارم. دليل بروز اين نگراني به اين موضوع برمي‌گردد كه افراد مي‌توانند به هر بخش كد شما كه مي‌خواهند، چيزهايي بيافزايند. بله به هر بخش كد و اين مي‌تواند باعث ايجاد يك 7Side effect شود. اين كار شما استدلال در مورد كدتان را بسيار مشكل مي‌كند».
 
در حقيقت، بيشتر نگراني‌ها درباره AOP به دو موضوع پيچيده بودن استدلال و تأثيرات ناخواسته زيان‌بار نويسنده Aspect برمي‌گردد. هرچند كه ابداع‌كنندگان AOP ادعا مي‌كنند كه با استفاده از AOP و به دليل تجمع كل جريان كاري Cross-Cutting Concernها در يك فايل، توانايي استدلال در مورد كد بالا مي‌رود، اما بايد پذيرفت كه اشكالات مطرح شده كاملاً قابل وقوع است و بايد درباره آن تصميماتي اتخاذ شود.

علاوه بر اشكالاتي كه ممكن است از طرف برنامه‌نويسي كه Aspectها را مي‌نويسد پيش آيد، برنامه‌نويس بخش اصلي نيز ممكن است با تغيير join pointهاي پيش‌بيني شده (مثلاً با تغيير نام آن‌ها) باعث ايجاد مشكلاتي شود كه برنامه‌نويس Aspect از آن بي‌خبر است.
 
اين دسته از نگراني‌ها درباره عدم هماهنگي بين برنامه‌نويسان بخش‌هاي مختلف و توانايي اثرگذاري بالا در يك سيستم، دغدغه  اصلي مهندسان نرم‌افزاري است كه به AOP مي‌انديشند. تمام اين موارد، اين واقعيت را بيشتر نمايان مي‌سازد؛ برنامه‌نويساني كه از AOP استفاده مي‌كنند بايد از تمام پتانسيل‌هاي آن اطلاع كامل داشته باشند تا بتوانند برنامه‌هايي به دور از مشكلاتي كه در بالا ذكر شد، ايجاد كنند.

در شماره‌هاي بعد به‌طور تخصصي‌تري به AOP مي‌پردازيم و سعي خواهيم كرد جنبه‌هاي عملي آن را بيشتر بيان كنيم.

 

منابع:

 http://www-106.ibm.com/developerworks/rational/library/2782.html-
http://www.theregister.co.uk/2006/10/26/aspects_java_aop-
http://home.comcast.net/~refilman/text/oif/aop-is2.pdf-
http://www.ibm.com/developerworks/rational/library/mar06/pollice/index.html-
http://www.developer.com/design/article.php/3308941
http://www.shabakeh-mag.com/Articles/Show.aspx?n=1003759&p=3
http://www.articles.ir/article2572.aspx

 


ارسال مقاله جدید | ویرایش این مقاله | ایمیل برای دیگران
[lnkIDC] Bookmark and Share   

  رای شما به این مقاله






  نظر شما درباره این مقاله چیست؟

 
نام:

 
نظر:

  نظرات
Ealdorman
man khaily vaghte ke donbale ye hamchin matlabi migardam mam by
امیر محمد
مقاله خیلی خوبی بود ممنونم کاش میشد راجع به نصبش هم یه چیزی می گفتید!!!
afshin
very very very good
قزاقی
بسیار مفید بود.

  مقالات مشابه:
مقاله مشابهی یافت نشد.  

Free counter and web stats
استفاده از مقالات پی سی پدیا در سایر رسانه های اینترنتی و چاپی با ذکر منبع و درج لینک آزاد است
درباره ما | تماس با ما | FAQ |
© 2006 - 2012 PCPedia.ir| Broadcast your knowledge™ | All rights reserved.