خلاصه کتاب Pragmatic Programmer. درس 23

درس 23: Design by Contractسر و کله زدن با سیستم های کامپیوتری سخته، سر و کله زدن با مردم سخت تر. ما مدت های مدید توی حوزه روابط و معاملات انسانی ریسرچ کردیم، روش های زیادی هم مطالعه، تست و اجرا شده، تو این درس میخایم یکی از بهترین روش ها که برای حوزه نرم افزار موثر و کاربردیه بیان کنیم و اون هم معامله بر اساس قرارداده.یک قرارداد مسئولیت ها و حق و حقوق طرفین قراردادو مشخص میکنه، همچنین توافق نامه ای همه جانبه است که شرایط شکست در هر یک از مسئولیت ها نیز مشخص میشه توش.قرارداد چه رسمی و چه غیررسمی به ساختار و معاملات کمک میکنه، آیا میتونیم ازش توی کدنویسی بهره ببریم؟ "بله"· DBC (طراحی براساس قرارداد)اولین بار این کانسپت توسط برتنارد میر در کتاب ساخت نرم افزار شی گرا در سال 1997 و با زبون برنامه نویسی ایفل، گفته شد. یک تکنیک ساده و در عین حال قدرتمند که براساس داکیومنت سازی دقیق از امکانات نرم افزار و توافق روی اون، به شکلی که نه کار اضافه تر و نه کمتری طبق قرارداد انجام بشه توسط طرفین اون، و داکیومنت سازی هم قلب این روش دیزاین بای کانترکت هست.هر تابع و فانکشنی که توی نرم افزار نوشته میشه، قبل از شروع و در حین عملیاتش با یکسری اکسپشن هایی در دنیای واقعی مواجهه که برتنارد این مدلی بیان میکنه:- Preconditionچه چیزهایی باید درست باشد تا فانکشن مورد نظر اجرا بشود، یک فانکشن هیچ وقت نباید کال بشه مادامی که پیش شرایطش یا دیتای مورد نیاز به شکل درست آماده باشه.- PostConditionفانکشن مورد نظر چه چیزی رو تضمین میکنه که بعد از اجرا انجام داده باشه.- Class Invariantsیک کلاس برای متغیرهای ثابتش باید تضمین کنه که مقدارشون معتبر و غیر قابل نوشتن باشه یا برای مدلهای مختلف متغیر براساس قوانین اون زبون برنامه نویسی** و به طور کلی قرارداد بین شونو میشه اینجوری بیان کرد، اگر فراخوانی کننده یک فانکشن پیش شرطهای یک فانکشن رو به درستی رعایت و اماده کنه، اون فانکشن تضمین و گارانتی میکنه که پس شرایط و یا همون خروجی و عملیاتهایی که باید رو درست انجام بده و مقادیر متغیرهای کلاس نیز معتبر باشند.بعضی از زبونای برنامه نویسی این کانسپت قراردادو ملموس تر ارائه میدن، مثلا زبون برنامه نویسی Clojure ، در مورد پیش شرط و پس شرطها قابلیت خوش دست و خوبی داره، یک مثال فانکشن واریز در عملیات بانکی رو میزنیم:(defn accept-deposit [account-id amount]{ :pre [ (> amount 0.00) (account-open? account-id) ]:post [ (contains? (account-transactions account-id) %) ] } "Accept a deposit and return the new transaction id";; Some other processing goes here...;; Return the newly created transaction:همونطور که میبینید دو تا پیش شرط داره یکی مبلغو چک میکنه مثبت باشه، و دومی اینکه حساب فعال و معتبر باشه، در پس شرط هم ارتباط بین شناسه تراکنش و حسابو تضمین میکنه.توی درس10 Orthogonality گفتیم کد خجالتی بزنید(برای دیکاپل کردن و رعایت اصل جداسازی)، توی این درس میخایم بگیم کد تنبل(lazy) بزنید.قبل از افتادن توی انجام کار و قول راجع به نحوه و کیفیت خروجی، به شدت روی ورودی ها و دیتکت مسئله سختگیر باشید. اگر قرارداد شما این مدلی باشه که همه چی قبوله، شمام باید توی خروجی قول جهان هستی رو به عنوان خروجی بدید و کلی ام کد بزنید.فرقی نمیکنه زبون برنامه نویسی که باهاش کار میکنید شی گراست یا فانکشنال، DBC شما رو فورس میکنه تا فکر کنید.· Class invariants and functional programmingاین اسم ثابت های کلاس رو برتنارد بخاطر این استفاده کرد که داشت از زبون برنامه نویسی ایفل که یک زبون شی گراست استفاده میکرد، اما مفهوم فراتر از اونه. این مفهوم به همون استیتها state ها اشاره میکنه، که یک اینستنس کلاس یک سری مقادیرو برای مشخص بودن استیتش نگهداری میکنه، توی زبونای فانکشنالم همینه، state و فانکشنها درگیر هستند.· پیاده سازی DBCبه زبان ساده، بررسی رنج ورودیها، شرطها، قولهایی که یک تابع برای انجامش داده، اگر به این ها فکر نکنید قبل از شروع پیاده سازی، قطعا با شکست های زیادی در پروژه مواجه میشید. و در بدو شروع هرچیزی fail میشید.توی زبونهای برنامه نویسی هم که دی بی سی رو ساپورت نمیکنن مثل اون درجه از ساپورتی که توی Clojure نشونتون دادیم، خوب نگران نباشید، DBC یک دیزاین پترن هست، شما میتونید تمام چک و تیک ها رو کد نویسی کنید یا در تست ها بیارید و به هر نحوی مطمئن بشید از رعایتشون.· Assertionsامکانی رو به شما میده برای چک کردن کامپایلری وضعیت های منطقی کد، آیا با اسرتها میتونید هر اونچه در DBC لازم دارید رو پیاده کنید؟ "نه"، به عنوان مثال زبونای برنامه نویسی از اسرتها در شی گرایی عمقی پشتیبانی نمیکنن، مثلا در ساده ترین حالت فرض کنید شما مشغول نوشتن کلاسی هستید که از کلاس پدری ارث میبره، و یک تابع رو اوررایت میکنید، و اسرت در تابع بیس نوشته شده، تو این شرایط اون اسرت برای تابع کلاس فرزند اجرا نخاهد شد و باید دوباره عین همون رو کپی کنید. اگر از اسرتها برای رعایت قرارداد توابع استفاده میکنید، باید کد رو به شکلی بنویسید که در پیش شرط، مقادیری که انتظار دارید از تابع برگرده رو سیو کنید تا بتونید مقایسه رو انجام بدید.· متغیرهای معناییفرض کنید در یک سیستم بانکی برای ثبت یک تراکنش واریز یا برداشت، این برای سیستم یک قانون مشخص و واضحه که نباید برای یک عملیات بیش از یک تراکنش ثبت بشه و اصطلاحا داپلیکیت وجود نداشته باشه، خوب اینو به عنوان قرارداد در کدتون اعمال میکنید، حالا فرض کنید با شرایط و قوانینی روبرو باشید که وابسته به شرایطن و ثابت نیستن، این مواردو توی فاز شناخت پروژه و داکیومنشن بایستی استخراج و در نظر بگیرید و برای چنین شرایط غیر ثابتی پالیسی و قوانینی پیاده سازی کنید.· قراردادهای پویا و ایجنت های خودمختارتاحالا راجع به قراردادهای ثابت و یا دارای شرایط و ضوابط صحبت کردیم، اما وقتی پای ایجنت های خودمختار وسط میاد داستان فرق میکنه. این مدل ایجنتها در سیستم میتونن هر درخواستی رو میخان رو ریجکت کنن، یا برای انجام چیزی مذاکره و منابعی رو درخواست کنن، با وجود این شرایط باز هم چنین سیستمی قطعا نیاز به قراردادها داره، فرض کنید یک سری کامپوننت و ایجنت که باهم در ارتباط و مذاکره هستن رو در یک سیستم داریم، که برای براورده کردن هدف نرم افزار طبق قراردادهای خاصی با هم ارتباط و رد و بدل دیتا میکنن، توی این حالت خوده نرم افزاره که انتخاب میکنه مسائلو به چه روشی حل بکنه.اما نکتش اینه که اگر ما از مدل DBC توی حالت دستی نتونیم استفاده کنیم، قطعا توی حالت اتومات هم نخاهیم توانست، پس اسبتونو زین کنید برای اینکه توی نرم افزار بعدی که مینویسید، این مدل رو پیاده کنید.دروس مرتبط: 24, 25, 38, 42, 43, 45منبع کانال تلگرامی: https://t.me/pragmaticprogrammer_fa