روی خط زندگی

گشت و گذار من در هنر نرم افزار

روی خط زندگی

گشت و گذار من در هنر نرم افزار

۶ مطلب با موضوع «Object Oriented Analysis and Design» ثبت شده است

همان طور که قبلا گفتیم، گام دوم در فرآیند تحلیل و طراحی به شیوه شی گرایی، تحلیل مساله و شرح و بسط آن است. برای این منظور با توجه به متدولوژی مورد استفاده می توان از UseCase و یا UserStory استفاده نمود. در ادامه به اختصار این دو را توضیح می دهیم:


Use Case چیست؟

با توجه به تعریف ویکی پدیا، Use Case لیستی از مراحل است که به شرح تعاملات یک کنشگر (Actor) با سیستم می پردازد. برای نوشتن یک Use Case شیوه های مختلفی وجود دارد از شیوه های بسیار مقرراتی که به طور مثال متدولوژی RUP پیشنهاد می کند تا گفتگو های آزاد به اصطلاح پینگ پونگی بین کنشگر (Actor) با سیستم.


به صورت کلی یک Use Case شامل سه بخش است:

1)عنوان: هدف از این مورد کاربرد (UseCase) چیست؟

2)کنشگر (Actor): چه کسی در این مورد با سیستم تعامل دارد؟

3)سناریو: شرح تعاملات کنشگر با سیستم


توجه داشته باشید که کنشگر (Actor) می تواند یک راهبر سیستم، کاربر سیستم و یا حتی یک وسیله (مانند یک ربات) یا سیستم دیگر باشد. 

نمونه ای از یک مورد کاربرد (Use Case):

عنوان: انتقال وجه

کنشگر: مشتری

سناریو: 

  • مشتری گزینه انتقال وجه را انتخاب می کند.
  • سیستم کاربر را به صفحه انتقال وجه هدایت می کند.
  • مشتری اطلاعات کارت بانکی و مبلغ مورد نظر را وارد می کند.
  • سیستم اطلاعات را ارزیابی می کند.
  • سیستم با استفاده از شبکه شتاب مشخصات کاربر انتقال گیرنده را بررسی می کند.
  • ....

توجه داشته باشید که در اینجا شرح Use Case به صورت دیالوگ های پینگ پونگی آمده است و می توان این شرح را حتی به صورت یک پاراگراف ساده توضیح داد. در صورتی که پیش شرایط یا قواعد خاصی برای این Use Case وجود داشته باشد هم می توان آنها را در انتهای سناریو تحت عناوینی چون پیش شرط یا محدوده اجرا یا غیره ذکر کرد. برای اطلاعات بیشتر می توان به مستندات RUP در مورد Use Case مراجعه کرد.


User Story چیست؟

در متدولوژی هایی مانند Scrum به جای Use Case از User Story استفاده می شود. User Story معمولا بسیار ساده تر از Use Case است و سعی دارد همان کار Use Case را به صورت موجزتر و دقیق تر انجام دهد. شکل کلی یک User Story به قرار زیر است:

به عنوان (یک کنشگر مثلا راهبر)

من می خواهم (هدف از این کنش)

تا (نتیجه مورد انتظار و ارزشی که برای کنشگر ایجاد می کند)


به طور مثال یک User Story نمونه می تواند به شکل زیر باشد:

به عنوان یک مشتری

من می خواهم با مراجعه به سایت بانک بتوانم امکان انتقال وجه به حساب شخص دیگری را به صورت آنلاین داشته باشم

تا مجبور به مراجعه به شعبه بانک نباشم.


لازم به ذکر است که انتخاب Use Case یا User Story به موارد زیادی منجمله قواعد متدولوژی مورد استفاده و یا رویکرد شما به عمق و شیوه تحلیل مساله بستگی دارد. ممکن است برای یک پروژه تصمیم بگیرید از Use Case استفاده کنید و برای پروژه دیگری از User Story و هیچ نسخه ای در این خصوص نمی توان پیچید.


۰ نظر موافقین ۰ مخالفین ۰ ۳۱ ارديبهشت ۹۴ ، ۲۱:۴۷
حسین گویا

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

این چک لیست را به اختصار FURPS و در روایت جدید تر +FURPS گویند. همان طور که گفتیم این چک لیست فقط یک یادآوری است که به ما می گوید آیا تا کنون در مورد این مطلب فکر کرده ای؟ آیا به این مطلب از این زاویه نگاه کرده ای؟ حال به شرح هر کدام از موارد FURPS می پردازیم:

  • Functional Requirements: همان نیاز مندی های کارکردی (یا تصریحی) است که در مطلب قبلی بدان اشاره شد.
  • Usability: مانند مستندات راهنما، مستندات آموزشی.
  • Reliability: برنامه ریزی برای آنچه که در زمان از کار افتادن سیستم باید انجام دهیم. مثلا اگر بانک اطلاعاتی از کار بیافتد چه گونه سرویس دهی به کاربران قطع نشود.
  • Performance: سیستم به چه حجمی از کاربران باید پاسخ دهد. زمان مناسب پاسخ دهی سیستم چقدر باید باشد.
  • Supportability: پشتیبانی سیستم پس از اجرا به چه نحوی خواهد بود. آیا به سیستم های جانبی دیگری برای پشتیبانی نیاز داریم، به طور مثال آیا برای کمک به کاربران سیستم، یک سیستم FAQ طراحی شده است؟


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

  • Design Requirement: به طور مثال سیستم باید برای موبایل و سیستم عامل اندروید طراحی شود.
  • Implementation Requirement: مثلا بانک اطلاعاتی سیستم چه باشد، SQL یا Oracle. و یا به طور مثال زبان برنامه نویسی سیستم چه باشد Java یا C#. 
  • Interface Requirement: این مورد تنها محدود به رابط کاربری نبوده و به این مطلب اشاره می کند که ارتباطات این سیستم با سایر سیستم ها چگونه است. به طور مثال برای یک وبلاگ آیا نیاز به RSS وجود دارد.
  • Physical Requirement: به طور مثال چه آرایشی از شبکه و سرورها برای اجرای سیستم مورد نیاز است. آیا سیستم به یک وب-کم احتیاج دارد؟


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


۰ نظر موافقین ۰ مخالفین ۰ ۲۴ ارديبهشت ۹۴ ، ۲۰:۱۶
حسین گویا

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

  • نیازمندی های تصریحی: نیازمندی های که مشتری راسا می گوید. مثلا رنگ ماشین خاکستری باشد.
  • نیازمندی های تلویحی: نیازمندی هایی که مشتری رسما نمی گوید ولی سیستم باید طبیعتا داشته باشد. مثلا یک خودرو طبیعتا باید سیستم ترمز داشته باشد.

در نرم افزار نیز نیازمندی ها به نوعی بر همین مبنا تقسیم می شوند:

  • نیازمندی های کارکردی (Functional Requirement)
  • نیازمندی های غیر کارکردی (Non Functional Requirement)

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

  1. راهنمای سیستم (Help): مستنداتی و آموزش هایی که برای یادگیری عملکرد سیستم مورد نیاز است.
  2. پشتیبانی (Support): آیا سیستم پس از اجرا به پشتیبانی نیاز دارد. اگر کسی ساعت دو نیمه شب با سیستم کار کند و به مشکل بر بخورد چه باید بکند.
  3. قوانین و مقررات (Legal): چه قوانین و مقرراتی بر پروژه حاکم است. مثلا قوانین کشوری یا وزارت خانه ای خاص که سیستم برای آن نوشته می شود.
  4. کارایی (Performance): سیستم به چه حجمی از کاربران باید پاسخ گو باشد و به قول معروف Response Time سیستم چه قدر باید باشد. مثلا ذات یک سیستم ثبت نام کنکور با سیستم ثبت نام یک آموزشگاه موسیقی متفاوت است.
  5. امنیت (Security): امنیت مقوله ای است که ممکن است بنا به نوع سیستم از نیاز مندی های اصلی باشد صراحتا گفته شود و یا جزو نیازمندی های غیر کارکردی و تلویحی لحاظ شود.

نمونه هایی از نیازمندی های کارکردی در سیستم های مختلف به قرار زیر است:

  • سیستم باید تنها به کاربرانی اجازه ورود بدهد که قبلا ثبت نام کرده اند.
  • سیستم باید در زمان ثبت نام کاربر، اطلاعات کلمه عبور را برای وی از طریق پیامک ارسال کند.
  • سیستم باید به کاربر اجازه ارسال پیامک به گروه های انتخابی از افراد را بدهد.
  • سیستم باید احراز هویت افراد را با کد ملی آنها از طریق سیستم ثبت احوال انجام دهد.

نمونه هایی از نیازمندی های غیر کارکردی به قرار زیر است:

  • یک راهنمای استفاده آنلاین برای کاربران تهیه شود و روی سایت قرار گیرد.
  • در صفحه ورود به سیستم (لاگین) یک Captcha قرار گیرد تا از حمله Brute force جلوگیری شود.
  • سیستم باید بتواند همزمان به یک صد هزار کاربر آنلاین پاسخ گو باشد.

۰ نظر موافقین ۰ مخالفین ۰ ۱۰ ارديبهشت ۹۴ ، ۱۹:۲۰
حسین گویا

وقتی می گوییم Object Oriented Analysis and Design منظور چیست و چه تفاوتی با Object Oriented Programming یا همان OOP دارد؟


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

Analysis (تحلیل): فهمیدن آن که مشکل چیست و چه راه حلی برای حل آن وجود دارد.

Design (طراحی): طراحی کردن مساله و برنامه ریزی برای حل آن.

Programming (برنامه نویسی): ساخت و پیاده سازی راه حل.

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


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

گام اول) شناسایی و جمع آوری نیازمندی ها

طبیعتا برای طراحی و پیاده سازی سیستم ابتدا باید بدانیم مشتری یا همان کارفرما چه می خواهد و چه انتظاراتی از سیستم دارد.


گام دوم) شرح و بسط مساله

یعنی سیستمی که می خواهیم بنویسیم چه کاری را می خواهد انجام دهد و چه امکاناتی دارد. برای انجام این مهم تکنیک ها و مستندات مختلفی وجود دارد. از قبیل Use Case و User Story


گام سوم) مشخص کردن اشیا وEntity  های اصلی 

این ها همان بازیگران اصلی سیستم هستند که با مشخص شدن آنها، گام اول برای طراحی کلاس ها را برداشته ایم. برای طی این مرحله از همان مستنداتی که در گام دوم ایجاد شده اند استفاده می کنیم (مانند Use Case و User Story) تا مفاهیم و اجزای اصلی سیستم که دامین پروژه را تشکیل می دهند، را بیابیم.


گام چهارم) طراحی ارتباطات و تعاملات این اجزا با یکدیگر

حال که در گام سوم اجزا را شناختیم، باید ارتباطات و تعاملات این اجزا را با هم و با جهان بیرون از سیستم، بیابیم. برای این کار می توانیم از نمودار های تعاملی UML مانند Swim lane و Sequence Diagram استفاده کنیم. این نمودار ها به ما کمک می کنند که وظایف و مسئولیت های اجزا و Object های مختلف سیستم را بهتر بشناسیم.


گام پنجم) طراحی کلاس دیاگرام (Class Diagram)

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


توجه داشته باشید که این پنج گام را تنها یکبار طی نخواهیم کرد و در هر گذار (Iteration یا Sprint) از عمر یک پروژه ممکن است دوباره این گام ها یا چند عدد از آنها را مجددا طی کنیم تا شناخت بهتری نسبت به سیستم بدست آوریم.


۰ نظر موافقین ۰ مخالفین ۰ ۲۷ فروردين ۹۴ ، ۲۲:۰۷
حسین گویا

GRASP مخفف General Responsibility Assignment Software Pattern است که همان طور که از نامش پیداست، به مبحث تعیین و توزیع مسئولیت ها بین موجودیت ها می پردازد. مانند اینکه چه کسی وظیفه تولید این اطلاعات را دارد، یا چه کسی مسئولیت نگه داری از اطلاعات را دارد، یا چه کسی باید پیام های ارسالی سیستم را مدیریت کند و مانند آن.


GRASP از نه عدد الگو تشکیل شده است. این نه الگو به ما کمک می کنند تا مسئولیت هر موجودیت در سیستم را تعیین کنیم:

1) Creator

چه کسی مسئول ایجاد یک شی است؟ برای یافتن فردی که این مسئولیت را به وی بدهیم سوالات زیر را می پرسیم:

  • آیا موجودیت این شی، موجودیت شی یا اشیای دیگری را هم ایجاب می کند؟ (همان رابطه Composition در نمودار کلاس ها)
  • آیا کلاسی هست که اطلاعات لازم برای تولید این شی را داشته باشد؟

2) Controller

هیچگاه مستقیما یک عنصر مرتبط با رابط کاربری (UI) را مستقیما به Business Class متصل نکنید (این امر یکی از دلایل افزایش Coupling می باشد). بهتر است یک کلاس Controller در بین آنها قرار دهیم که این دو با واسطه کلاس Controller به هم متصل شوند. الگوی MVC یکی از بهترین نمونه ها برای این مطلب است.


3) Pure Fabrication

اگر دیدید که یک مسئولیت قواره تن هیچ یک از کلاس های موجود نیست، بهتر آن است که یک کلاس جدید بسازیم و مسئولیت را به آن کلاس دهیم، چرا که در صورتی که مسئولیت مورد نظر را به یکی از کلاس های موجود بدهیم، در واقع Cohesion را کاهش داده ایم.


4) Information Expert

مسئولیت را به کسی (کلاسی) بدهیم که اطلاعات لازم برای انجام آن کار را در اختیار دارد.


5) High Cohesion

شاید اگر برای این یکی مثال عکس بزنم راحت تر بتوان توضیح داد، فرض کنید که یک کلاس داریم با تعداد بالایی از Property  ها و Method ها، که این Property ها و Method ها هیچ کاری با هم ندارند و هر کدام برای خودشان کار خود را انجام می دهند. این یعنی Low Cohesion که ناقض اصول طراحی شی گرا، مانند اصل تک مسئولیت ای (Single Responsibility) و God Object Code Smell است.


6) Indirection

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


7) Low Coupling

یعنی ارتباطات بین موجودیت ها را به نحوی کاهش دهیم که کمترین وابستگی را به یکدیگر داشته باشند. این بدان معنی نیست که موجودیت ها نباید هیچ وابستگی به هم داشته باشند، بلکه باید این وابستگی ها را تا حد ممکن کاهش داد.


8) Polymorphism

هر موجودیت، رفتار خودش را با توجه به نوع خود ، به صورت خودکار تعیین و اصلاح کند!


9) Protected Variation

ذات سیستم ها تغییر است. مهم نیست حجم تغییرات چه میزان ست، بلکه مهم آن است که سیستم را در برابر تغییرات ایمن سازی کنیم. اگر اصولی مانند وراثت، یا Open Close Principle (OCP) را رعایت کنیم، می توانیم تغییرات را در سیستم مدیریت کنیم.


۰ نظر موافقین ۱ مخالفین ۰ ۲۸ دی ۹۳ ، ۲۰:۴۳
حسین گویا

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


S: Single Responsibility Principle 

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

Single Responsibility Principle

O: Open / Close Principle

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

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

بهترین قاعده ای که در پیاده سازی این اصل به کار می آید، قاعده چند ریختی پویا یا Dynamic Polymorphism می باشد.یک مثال خوب در این مورد را می توانید در این آدرس ببینید.

Open Closed Principle

 

L: Liskov Substitution Principle

اصل جایگزینی لیسکوف، می گوید یک کلاس که از کلاس دیگری به ارث رفته است، باید بتواند، جایگزین کلاس والد شود. یک مثال کاربردی در این باب به شفاف تر شدن مطلب کمک می کند:

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

 Liskov Subtitution Principle

I: Interface Segregation Principle

چند interface خاص که هر کدام یک رفتار مشخصی را بیان می کنند، بهتر از یک interface عمومی است که رفتار های مختلفی دارد. چرا که کلاس هایی که از این interface استفاده می کنند، باید چندین رفتار را پیاده سازی کنند که شاید نیازی بدان ها نداشته باشند.

 Interface Segregation Principle

D: Dependency Inversion Principle

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

 Dependency Inversion Principle


۰ نظر موافقین ۱ مخالفین ۰ ۲۰ آذر ۹۳ ، ۱۹:۱۹
حسین گویا