برنامه نویسی محور آبجو در F # [1]

مقدمه

در این پست وبلاگ ، من به پستهای منظم اخترفیزیک خود سر می زنم و درمورد یک پروژه جانبی که من در آن کار کرده ام می نویسم تا هنگام بروزرسانی در انتخاب آبجو انتخابی منجمد من: Tired Hands. مشابه پست های قبلی من ، از F # با VS Code ، Mono ، Ionide ، PAKET و FAKE در مک استفاده می کنم.

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

خط لوله اصلی را شامل می شود:

  1. آخرین لیست آبجو را از وب سایت Tired Hand خراش دهید
  2. تفاوت بین خراش قبلی و جدید را با یکدیگر مقایسه کنید
  3. در صورت وجود اختلاف ، اعلان متن.

بسیار سپاسگزارم ، F #: خیلی جالب است که تلاش های نوشیدن آبجو را با استفاده از مفاهیم برنامه نویسی کاربردی بهبود بخشید [نام نویسان M * ، انواع داده های جبری ، تطبیق الگوی ، فقط چند مورد را ذکر کنید]

آرم از دست خسته

ایمپتوس

با الهام از پست های Scott Wlaschin درباره برنامه نویسی راه آهن در وب سایت عالی خود ، F # for Fun and Profit ، می خواستم ایده جدا کردن "مسیر ناخوشایند" از "مبارک" را در این پروژه به همراه سایر هدایای مربوط به ROP بگنجانم. ،

من همچنین می خواستم وقتی انتخاب آبجوهای Tired Hand از Fermentaria تغییر کرده است راهی پیدا کنم. بنابراین ، این نام فقط باید نمادی برای برنامه نویسی آبجو و راه آهن گرا باشد.

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

مبله کردن

ما با ایجاد یک پروژه جدید بر اساس پوشه ها و برنامه های کنسول با کد VS با عنوان "BeerwayOrientedProgramming" شروع می کنیم. برای ایجاد پروژه جدید ، پالت فرمان [Cmd + Shift + P] را باز کنید و کارهای زیر را انجام دهید:

نتیجه ایجاد پروژه جدید باعث می شود که فهرست جدید تازه ایجاد شده ما چیزی شبیه به این باشد:

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

  1. HtmlTypeProvider FSharp.Data به راحتی در وب سایت جستجو کنید تا سوابق مربوط به دامنه از آخرین اطلاعات آبجو را ایجاد کنید.
  2. Chiron ، کتابخانه ای برای همکاری با JSON در F # برای بی حس کردن اطلاعات آبجو از قراضه قبلی و سریال کردن آن برای نگه داشتن اطلاعات فعلی آبجو در آخرین ضایعات.
  3. Twilio API برای ارسال متن در مورد اختلاف بین پرونده قبلی و فعلی یافت شده است.
  4. Logary ، بازارچه ای از کتابخانه ورود به سیستم که معیارهایی نیز ارائه می دهد. [در پست بعدی استفاده می شود]
  5. FSharp.Configuration برای تجزیه و تحلیل پرونده پیکربندی برای حساب کاربری Twilio API SID و شناسه تأیید اعتبار و همچنین فاصله بین تماسهای برگشتی تایمر. [در پست بعدی استفاده می شود]

بعد از باز کردن پرونده fsproj برای اولین بار ، همه وابستگی های فوق را با PACKAGE اضافه خواهیم کرد. برای نشان دادن اضافه کردن وابستگی از طریق PACKAGE ، از افزودن Chiron به پروژه به عنوان نمونه استفاده می شود.

با اطمینان از این که آخرین مرجع اضافه شده منجر به پرونده های fsproj ، paket.references و بسته های paket.d وابستگی می شود ، می توانیم بررسی کنیم که آیا وابستگی با موفقیت اضافه شده است.

برنامه نویسی راه آهن محور

برنامه نویسی مسیر گرا روشی تمیز ، نیرومند و کاربردی برای مقابله با مسیر تاسف بار است. مسیر تاسف بار ، مسیر کل smorgasbord استثنائات ، خطاها و اشک است. ارائه ای که واقعاً در مورد این موضوع توسط Scott Wlaschin عدالت برقرار کند را می توان در اینجا یافت.

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

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

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

ما با ایجاد یک پرونده جدید به نام ROP.fs که شامل تمام ویژگی های برنامه نویسی راه آهن ما است ، پرونده جدیدی به پروژه اضافه می کنیم:

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

کد این ماژول به این شکل است: من آن را از ارائه و پست وبلاگ دزدیدم. می توانید اطلاعات بیشتری در آنجا بیابید. همانطور که قبلاً نیز اشاره شد ، از نظر مشارکت و ارائه آقای ولاسچین ، منابع بهتری وجود ندارد.

دامنه

ما نوع اصلی رکورد خود "BeerInfo" را طوری تعریف می کنیم که از "TimeOfScrape" ، یک DateTime و "آبجو" تشکیل شود ، لیستی از رشته ها که نشان دهنده همه آبجوها از این ضایعات است.

برای استفاده از Chiron ، باید دو عضو ثابت تعریف شود: ToJson و FromJson برای سریال کردن و deserialize کردن نوع BeerInfo. اطلاعات بیشتر در مورد نحوه کار Chiron را می توان در اینجا یافت.

هدف

پس از تعریف دامنه خود ، هدف خود را تعریف می کنیم تا بتوانیم موارد زیر را به ترتیب انجام دهیم:

  1. می توانید گزیده ای از آبجو را در وب سایت Tired Hand پیدا کنید. موفقیت زمانی است که ما با موفقیت رکورد BeerInfo را از آخرین ضایعات بازیابی کنیم. خطا یک ScrapeError است که می تواند توسط یک استثناء وب ایجاد شود ، به عنوان مثال به عنوان مثال ، درخواست به موقع یا دسترسی غیرمجاز به وب سایت پایان داد.
  2. نتایج آخرین خراش را با نتایج قبلی مقایسه کرده و اختلافاتی را پیدا کنید. موفقیت زمانی است که بین اولین و آخرین خراش اختلاف وجود دارد. اگر هیچ تفاوتی بین خراشیدن یا مقایسه ای با یک استثناء I / O وجود نداشته باشد خطای NoDifference خطا است در حالی که نتایج قبلی ضایعات به صورت غیرقانونی و یا آخرین نتایج ضبط سریالی می شوند.
  3. در صورت مشاهده تفاوت در انتخاب آبجو ، از طریق پیامک به ما اطلاع دهید. موفقیت فرایند ارسال موفقیت آمیز متن است و هنگام بروز یک استثناء API ، هنگام ورود نادرست یا محدودیت های ضربت ، خطایی هشدار دهنده است.

خط لوله ما باید به شرح زیر باشد:

خراش> => مقایسه> => زنگ

ما با ایجاد یک پرونده جدید خطاهای هر مرحله را اضافه می کنیم: Common.fs با ماژول های اجزای مشترک ما که به ترتیب کامپایل شده تحت ROP.fs منتقل شده اند:

Scrap: scraping و نوع ارائه دهنده

ارائه دهندگان نوع یکی از اصلی ترین دلایلی است که من تصمیم گرفتم که چگونه در F # را توسعه دهم. من با الهام از یک نمایش گسترده از راشل ریز [دسامبر 2015 در فیلادلفیا] ، با ثبت نام در F # به عنوان دشمن حالت کنترل نشده کنترل ، راهی یک سفر خستگی ناپذیر شدم.

ما از کتابخانه ارائه دهنده عالی HTML در کتابخانه FSharp.Data استفاده می کنیم ، که باید در هنگام تنظیم پروژه از طریق گشت و گذار PACKAGE ما آن را بارگیری کنیم. ما با اضافه کردن پرونده جدید "TiredHandsScraper.fs" که شامل توابع اختصاصی TiredHands ما است ، شروع می کنیم و سپس این پرونده را روی BeerwayOrientedProgramming.fs انتقال می دهیم ، که حاوی نقطه ورود و عملکرد اصلی ما است.

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

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

اکنون همه مؤلفه های خود را برای ایجاد تابع scrape داریم که موفقیت یک BeerInfo را در صورت عدم استثناء قراضه یا خطایی در پیام استثناء scrap ، برمی گرداند. این عملکرد مانند این است:

در اینجا مثالی از نتیجه عملکرد خراش در 15 ژوئیه 2017 آورده شده است:

موفقیت {TimeOfScrape = 07/15/2017 02:25:35؛ آبجو = ["HopHands"؛ "SaisonHands"؛ "آرزوی تحقق"؛ "کلیسای بیگانه"؛ "پیشرفت از طریق Unlearning II"؛ "اله ره"؛ "Trendler Pilsner"؛ "Ridiculoid"؛ "کار کردن انتظارات"؛ "جمع کننده 2017"؛ "هارمونی اجباری"؛ "قهوه بیدار شوید"؛ "چای یخ زده دارجیلینگ"؛ "PopHands سودا پاپ"؛ "انتخاب بطری در خانه"؛ "Ourison"؛ "کثیف"؛ "چشم بسته و باز"؛ "ساکشن"؛ "Obelisk Hysterical"؛ "فراموشی"؛ "سنگین سنگین ویرگا"]؛}

بله ، من می دانم که باید بخوابم.

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

قدم بعدی ما نوشتن تابع مقایسه ما است که:

  1. خراش های قبلی را deserialize می کند. برای ساده نگه داشتن چیزها ، فقط JSON را سریال می کنم و آنرا روی پرونده ای بنام "TiredHandsScrape.json" می نویسم. اگر این پرونده یافت نشد ، به طور خودکار در مرحله 4 ایجاد می شود
  2. آبجوها را از خراش قبلی با نمونه فعلی مقایسه می کند ، با استفاده از Set Differences برای یافتن آبجو در خراش فعلی که در خراش قبلی نیست
  3. موفقیتی را شامل می شود که شامل تفاوت یا خطای یک مقایسه مقایسه یا یک NoDifference است
  4. نتیجه ضایعات را به صورت سریالی سازی می کند تا بعنوان اطلاعات ضایعات قبلی BeerInfo برای دیگری استفاده کند و آن را در پرونده TiredHandsScrape.json ذخیره می کند.

ما توابع مربوط به این مرحله مقایسه را به یک ماژول جداگانه در Common.fs با عنوان مقایسه می رسانیم.

به طور کلی ، این ماژول مانند این است:

پرونده TiredHandsScrape.json JSON از خراش بعدی با عملکرد مقایسه به شرح زیر است:

{"آبجو": ["HopHands" ، "SaisonHands" ، "آرزو برآورده" ، "کلیسای بیگانه" ، "پیشرفت از طریق یادگیری II" ، "Aloha Ra" ، "Trendler Pilsner" ، "Ridiculoid" ، "عملی کردن انتظارات" ، " جمع کننده 2017 "،" هارمونی اجباری "،" قهوه بیدار ذهن "،" چای یخ زده دار "،" PopHands سودا پاپ "،" در انتخاب بطری های خانه "،" اوریسون "،" هرج و مرج "،" چشمان بسته و باز "،" ساکشن "،" چاقی هیستریک "،" Obliterative "،" سنگین سنگهای قیمتی ویرگا "] ،" TimeOfScrape ": 2017-07-15T13: 21: 00.8194460Z

می دانم که کدنویسی نام یک فایل متنی احتمالاً بهترین ایده نیست ، اما نگران نباشید ، ما این پست را در پست وبلاگ بعدی عمومی تر خواهیم کرد.

هشدار: ارسال یک متن از طریق API Twilio

توسعه آخرین عنصر در خط لوله بسیار ساده است زیرا استفاده از API Twilio نسبتاً آسان است.

Twilio یک "بستر ارتباطی ابری برای ایجاد برنامه های پیام کوتاه ، صوتی و پیام رسانی در API است که برای مقیاس جهانی طراحی شده است".

ما با ایجاد یک ماژول جدید به نام "Alert" در پرونده Common.fs خود شروع می کنیم و از API C # Twilio استفاده می کنیم تا در صورت وجود اختلاف بین دو اسکریپت متن ما را ارسال کند. یک مکان عالی برای شروع اینجا است. پس از تنظیم یک حساب کاربری و دریافت شماره تلفن ، SID حساب و نشان تأیید اعتبار برای استفاده ، باید بتوانید ارسال پیام های متنی را شروع کنید.

کد این ماژول مانند این است:

باز هم ، ما خیلی دوست داریم به جای رمزگذاری اطلاعات Twilio برای ارسال متن ، یک فایل پیکربندی ایجاد کنیم.

نکته جانبی: من سعی کردم نام پارامترها را به تابع ایجاد اضافه کنم ، اما نمی توانم به این دلیل که اولین نام پارامتر "to" است ، کلمه کلیدی زبان F # است که برای حلقه استفاده می شود. جزئیات بیشتر در اینجا شاید راهی برای انجام این کار وجود داشته باشد؟

خط لوله: همه چیز را با هم گره بزنید

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

این فرایند ترکیبی بسیار ساده است: تمام کاری که ما باید انجام دهیم این است که مقداری برنامه نویسی راه‌آهن گرا را در این گلدان ذوب توابع ماژول اعمال کنیم. به طور کلی ، BeerwayOrientedProgramming.fs مانند این است:

خوب و ساده و در عین حال به اندازه کافی قدرتمند برای رفع همه اشتباهات ما ، اینطور نیست؟

برای ساختن ، از FAKE برای ساختن پروژه خود با باز کردن پالت فرمان [Cmd + Shift + P] استفاده می کنیم:

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

در مرحله بعد ، برنامه را با استفاده از Mono از پوسته خود به روش زیر اجرا می کنیم و دایرکتوری ها را تغییر می دهیم تا به فهرست اصلی BeerwayOrientedProgramming خود برسیم. پوشه build شامل DLL های تازه پخته شده و نمونه اصلی ما:

mono build / BeerwayOrientedProgramming.exe

اگر تفاوتی در انتخاب آبجو نباشد ، دریافت می کنیم:

عدم موفقیت NoDifference

وقتی برنامه خود را برای اولین بار اجرا می کنیم یا تفاوت هایی با ضبط قبلی وجود دارد ، از خط فرمان موارد زیر را دریافت می کنیم:

موفقیت "پیام جدید با موفقیت ارسال شد"

و هنگامی که ستاره ها تراز می شوند ، متنی شبیه به موارد زیر می گیریم:

عیب یابی

ترتیب تدوین در پرونده fsproj ما باید به صورت زیر باشد:

اگر تلفیق انجام نشود ، باید اطمینان حاصل کنیم که ترتیب تلفیق مشابه است. توجه داشته باشید که BeerInfo.fs و ROP.fs می توانند مبادله شوند زیرا مستقل از سایر ماژول ها هستند.

مشکل دیگر ، ورود نادرست جزئیات Twilio API است که باید از طریق خط لوله قوی ما به راحتی شناسایی شود.

مراحل بعدی

اکنون که ما یک خط لوله اصلی ایجاد کرده ایم ، می خواهیم چند ویژگی دیگر اضافه کنیم ، یعنی:

  1. پیکربندی ها را طوری تنظیم کنید که هیچکدام از این تمرکز های متمرکز و هکوس سخت ادامه پیدا نکنند
  2. ثبت نتایج در طول مسیر؛ این امر به ویژه در شرایطی که نشانه گذاری به طور قابل توجهی تغییر می کند و هیچ نتیجه ای نمایش داده نمی شود مفید است. علاوه بر این ، ممکن است بخواهیم از رگرسیون برای پیش بینی الگوهای انتشار آبجو بر اساس اطلاعات گزارش استفاده کنیم
  3. برنامه ریزی کنید تا روند به موقع اجرا شود
  4. تعمیم برنامه زمانبندی اجرای خط لوله برای چندین کارخانه آبجو
  5. تست عملکردهای ROP ما
  6. گردش همه کاره ناهمزمان را برای همه فعل و انفعالات I / O ما اضافه کنید.

ما در پست آینده این موضوع را مورد بحث قرار خواهیم داد. بنابراین به روز باشید.

نتیجه گیری

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

کد این پروژه را می توان در اینجا یافت. من کد مخصوص این پست وبلاگ را در شعبه "blogpost1" اضافه کردم.

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

با تشکر بیشتر از همکار دیوانه من ، نیک A ، که این ایده را مورد توجه من قرار داد ، و به Tired Hands Beer.