От мейнфрейм COBOL до обектно-ориентираната бездна: Динозавърът реве

Вие сте това, което ядете

Някой друг гладен ли е? Наближавам края на третия и последен месец от програмата ChiPy Spring Mentorship, чрез която уча Python (и много повече) и изглежда колкото повече се задълбочавам, толкова повече искам да консумирам! Моят набор от умения в тези модерни технологии нараства всеки ден и се забавлявам да научавам нови неща и да ги използвам.

Откакто публикувах последния си блог, се вливах в моя проект и в резултат на това не само имам работещо уеб приложение, но научавам още повече за Python, както и за други известни технологии като AWS Cloud. Моят уебсайт може да се използва за извличане на статистика в реално време от сървъра на MLB Gameday Data. За да направя това да се случи, написах моя собствена логика за извличане на тези данни от огромна колекция от JSON речници на техния сървър, тъй като средният фен няма достъп до MLB API. Това беше прикрита благословия, тъй като се научих да пиша API на Python и как да ги извиквам от уеб сървъра. С това, нека навлезем в изперкалите подробности! 🤓

Инфраструктурата

Избрах да поставя този сайт в облака на AWS поради важни обекти в живота ми, които се движат в тази посока, и определено би било още едно страхотно умение, което да имам в арсенала си. AWS Elastic Beanstalk е инструмент за внедряване и мащабиране на уеб приложения и изисква Python 3.4, така че виртуалната среда, която създадох, за да разработя този уебсайт, трябваше леко да се понижи от моята базова инсталация 3.6.

Създадох уеб приложението с помощта на рамката на Python Flask. Това беше шут да разбера дори с многото уроци за Flask, които намерих в мрежата. Лесно разбрах метода за маршрутизиране, но предаването на данни към/от формуляра и как правилно да се препратят тези полета, особено предвид нюансите, присъщи на една многофункционална страница, която проектирах, беше трудно да разбера! Но след много часове четене, опити и грешки и от време на време F-бомба 💣, аз надделях и данните потекоха в страницата като вода над Ниагарския водопад.

Бързи пътища към данните

След като проучих MLB сървъра, избрах да създам 3 файла, доставящи на уеб приложението голяма част от тази информация, и също така ще насоча приложението към данните в реално време на MLB сървъра, когато бъде поискано. Два ключови MLB файла задвижиха тази настройка...

Главно табло с резултати: Има едно срещане на този файл за всеки ден и заровен дълбоко вътре е графикът на всички игри за този ден. Той не само съдържа информация за играта, но също така има директория, където могат да бъдат намерени файловете за всяка игра! Това се оказа решаващо за начина, по който проектирах бекенд и уеб процеси, които да се управляват от тези данни. #thankyouMLB

По-долу е само мъничко, мъничко парче от файла с главното табло от 20 юни и подчертах област, позоваваща се на играта Cubs vs Padres. Обърнете внимание на ключовата дума на речника „game_data_directory“ и нейната стойност е дълго име на директория, което използвам, за да намеря файла boxscore за тази конкретна игра.

Boxscore: Един от тези файлове съществува за всяка игра, играна в даден ден, и съществува в директория, специфична за тази игра. Ако отборите играят двоен хедър, ще има отделни директории и резултати за всяка игра. Това е мястото, където намерих статистика на играчите, специфични за тази игра, както и техните статистики за сезона. Единственото предупреждение тук, което наистина ме принуди да създам главен файл на играча, беше, че речникът на Boxscore изброява само играчи, които са играли в играта. Така че, ако искам да потърся статистиката на Tommy La Stella и той не е играл днес, ще трябва да търся в речниците на boxscore, връщайки се назад във времето, ден след ден, докато намеря последната игра, в която е играл, за да мога да извлека точната му статистика за сезона. Оттук и необходимостта от създаване на майстор на играча. #uuggghhh

Необходими Backend процеси

Така че въз основа на горното написах бекенд процеси за създаване и актуализиране на три файла; файл с дневен график, съдържащ връзки към всички днешни игри и два главни файла (играчи и отбори), които използват файла с графика, за да намерят пътя си в безбройните данни. Тези файлове са изградени от файловете boxscore във фонов режим през целия ден и се превърнаха в изходни данни за голяма част от уеб приложението, тъй като повечето заявки са за екипни и сезонни данни. Едва когато бъде направена заявка за извличане на днешната статистика, трябва отново да вляза в boxscore на MLB сървъра, за да изтегля тази актуална статистика.

Изглежда логично процес на актуализиране на главен файл като този да трябва да се изпълнява само веднъж на ден, но благодарение на това как данните се актуализират на сървъра на Gameday, информацията не е достъпна наведнъж. Информацията за играта и състава се просмуква и не е пълна до около час преди началото на играта. Информацията за графика е налице в началото на деня, но директориите може още да не са създадени и дори да бяха речникът на boxscore за всяка игра, може все още да не е създаден и дори да са готови, съставите може да не са били въведени още. Това наистина наложи непрекъснат процес на актуализиране през целия ден, така че да имам налична информация за показване по всяко време. #thanksagainMLB

Създадох главните речници с помощта на JSON. Отляво е входът за Мадисън Бъмгарнър от Сан Франциско Джайънтс. На всеки MLB играч се присвоява уникален „код“, който обикновено е неговото фамилно име, освен ако няколко играча имат едно и също фамилно име, в който случай се добавя част от първото име, за да ги направи уникални. Оттам виждате основна информация на следващото ниво заедно с два вложени речника, един за удар и един за хвърляне.

Уеб приложението

Използвайки Flask, моделирах скриптовете около това, което научих от урока за Mega Flask. Има уеб сървър, който чака HTTP заявки от външен порт и насочва всяка заявка вътрешно към конкретно място в главния модул. Това беше страхотно, тъй като можех лесно да видя как действията, предприети в уеб страницата (щракване, изпращане и т.н.), се насочват към съответната функция за обработка на заявката и, ако е необходимо, пренасочване към друго място в модула, подходящо за следващата част от запитването. По-долу е моментна снимка на маршрутизирането и кода за страниците Home и Display By Team.

С уеб приложенията идват API и трябваше да напиша няколко от тях за този сайт. Повечето от API извличат данни от главните файлове, описани по-рано, но някои противоречат на данните в реално време, налични на MLB сървъра, за да получат цялата важна актуална статистика. Архитектурата е интересна, тъй като подобен, но отделен сървър се инициира, за да обработва API заявките, идващи от уеб сървъра.

Смешно нещо се случи по пътя към форума на API. Открих, че независимо кой тип данни върнах от API, трябваше първо да го декодирам, като преобразувам резултата от байтов низ в символен низ (unicode). След това мога да презаредя низа в JSON речник, за да захраня моите формуляри… което е, което API предаде обратно на извикващия модул на първо място. 😑

Всичко се връща като тип данни Byte String. В крайна сметка това не беше голяма работа да добавя още два реда магия на Python за декодиране на данните и презареждане на речника, но представете си разочарованието ми, тъй като във всеки урок и блог, който прочетох, не се споменава тази важна малка част от информацията! IPython беше моето спасение за това и много други проблеми, през които трябваше да се справя.

Здравейте Web App Junction, каква е вашата функция?

Казано по-просто, уебсайтът е механизъм за извличане и показване на статистически данни за MLB играчи чрез предварително дефинирани методи, всеки от които отвежда потребителя по малко по-различен път, за да стигне до желаните данни. И двата пътя водят до показване на списък с играчи заедно със статистиката им за сезона. Ако в този момент бъде избран играч, тогава системата ще извлече и покаже актуалната статистика от днешния файл с boxscore.

По отбор: Щракнете върху бутона По отбор и всичките 30 MLB отбора ще бъдат показани по азбучен ред заедно с техния рекорд, днешния опонент и местното време, в което играят (и двете времена на играта се показват, ако има двойно заглавие). След това щракнете върху отбор и всички играчи за този отбор и ще се покажат, групирани в категории Удари и Накланяния и сортирани по фамилно име във всяка категория, показвайки подходящата статистика.

По фамилия: Щракнете върху бутона По фамилия и се отваря поле за въвеждане на част от фамилията на играча (изисква се минимум 1 буква). Щракнете върху Търсене Име и статистиките за сезона за всеки играч, чието фамилно име съответства на въведения начален шаблон, ще се покажат, групирани по категории Удари и Накланяния и сортирани по фамилия във всяка категория, показваща подходящата статистика.

Независимо от метода, използван за показване на статистиката за сезона за списък с играчи, днешната статистика за вече завършени или протичащи игри е само на едно кликване. Написах много страхотен HTML код, за да подчертая реда на играча, и го направих с възможност за кликване, за да изпратите заявката, за да видите днешната статистика. Мога да стигна до данните в реално време много бързо, тъй като избраният играч има асоцииран код на отбора, който сочи към записа на този отбор в главния файл на отбора, който съдържа директориите за днешните игри, където ще намеря файла boxscore, съдържащ днешния статистика. Малко предварителна работа по проектиране може да извърви много дълъг път в разработването на ефективни системи.

Списъкът за наблюдение: Това е епична функция, която се надявам да завърша до големия танц на 13 юли. Чрез тази функция вие избирате играчи, които да бъдат наблюдавани, въвеждате телефонния си номер и всеки път, когато ударят хоумрън, системата ще ви изпрати съобщение. Този процес ще използва още един MLB речник, наречен Game Events log, докато сканира за хоумрънове, ударени от вашите любими играчи. Слава богу, току-що получихме кредит от $20 от страхотния ни спонсор Twilio, за да получим 2500 безплатни съобщения! Сега, когато имаме допълнителна седмица, се надявам, че мога да използвам тези 2500 съобщения чудесно!

Ето връзката към папката на проекта в моя GitHub акаунт. Чувствайте се свободни да разглеждате и да се обръщате с всякакви въпроси, имайте предвид, че сайтът все още е в процес на изграждане, но е адски близо до завършването!



Отклоних се, нещо като...

В понеделник вечер седях на лявата трибуна на Wrigley Field и гледах мача на Cubs с дъщеря ми Ашли. Неделя беше Ден на бащата и ние продължихме празника в понеделник, който нарекохме Ден на Падрес. Имаше завръщане в края на мача от нашите герои от родния град и някаква драма от 9-ия ининг и Cubs удържаха да победят Padres, което донесе много радост на публиката в Mudville. Но по време на играта, когато не бях въвлечен в разговор или бях въвлечен в луди скандирания с Bleacher Bums, задната част на ума ми работеше върху проблем сред затишията между инингите.

По-рано през деня видях проблем, публикуван в нов slack канал (#code-talk), който произхожда от някакъв курс на MIT и изглеждаше като забавно предизвикателство. Не можах да устоя на изкушението да разбера това, тъй като обичам да решавам проблеми. Почти веднага разбрах, че това може лесно да се реши с мощна техника, наречена рекурсия, и направих няколко бележки. Дъщеря ми погледна към това, което драсках в бележника на телефона си, и попита: „Какво, по дяволите, е това?“ На което аз отговорих: „Ами… това е Python!“

Не ме питайте защо, но умът ми просто прави тези неща и когато се доближи до измислянето на нещо, той продължава да бълва идеи на заден план, докато не получа решение. Какво общо има това с моето уеб приложение? Не е нищо, но в предишните два блога сравних света на мейнфрейм COBOL, от който дойде този динозавър, със света на Python/Object Oriented, през който сега пътувам, и ще направя същото отново тук. Този път обаче ще сравня кода и ще ви покажа решения, които съм написал както на Python, така и на COBOL, за да можете да видите разликите.

Днешната битка за титлата, Python срещу COBOL!

Проблемът беше следният: използвайки низа „azcbobobegghakl“ като вход, напишете код на Python, за да намерите най-дългия низ от знаци във възходящ азбучен ред и връзките се броят. Буквите не трябва да са последователни, само в ред и ако една и съща буква се повтаря една до друга, това се счита за ред. Като се има предвид цитираният входен низ, правилният отговор е beggh.

Първо, епичното решение на Python...

Забележете използването на рекурсивните функции и как и двете се извикват, за да съкратят низа, който в момента се изследва, докато не свършат буквите. Функцията search_next_letter_in_s разглежда всяка буква в s (запомнящо се име, а?) една по една и извиква search_rest_of_s, за да разгледа останалата част от s, за да намери най-дългия низ в азбучен ред от този момент нататък.

Едно интересно нещо, което трябва да се отбележи за това решение е, че не са използвани цикли for или while за задвижване на този процес. Това беше самоуправляващ се цикъл, захранван само от рекурсия. Освен това не е извършена математика за манипулиране на индекси, сочещи към текущия срез в рамките на проверявания низ. Всъщност единствената операция, която добави нещо, беше конкатенацията на следващата буква в s към низа current_long. Можете да промените низа s на всичко, дори само на една буква или нула, и пак работи!

И сега моментът, който всички сте чакали… решението на COBOL!

Това, което виждате отляво, е само предговорът към действителната логика. В COBOL трябва да кажем на програмата, че работи на IBM 370 архитектура (мейнфреймът IBM 370 е създаден през 1970 г. и оттогава е претърпял огромни подобрения). Също така трябва да дефинираме всички променливи, използвани в програмата, техните размери, типове данни и всякакви първоначални стойности. Трябва да се свърши много работа, преди да започне истинската работа и това е само малък пример!

Така че сега действителната логика за решаване на проблема...

Тук циклите са много, докато в Python успях да кодирам без тях, не че има нещо лошо в това. Не можех да използвам рекурсия… е, можех, но нека ви кажа колко много работа би наложило това.

Първо, ще трябва да напиша две други програми, една за параграфа, който се занимава с s, и една за останалата част от s. Програмите биха се наричали много подобно на еквивалентните функции на Python, които написах. Всяка програма ще се нуждае от повтаряне на всички скучни неща, които разказват на COBOL за средата на IBM 370 и други забавни неща, които умира от желание да знае.

След това ще трябва да дефинирам това, което наричаме комуникационна зона (комуникационна зона). Това е мястото, където дефинирате всички полета, които се предават напред-назад между две програми, и за да продължа с това, трябва също да кодирам секция за свързване, където се намира дефиницията на зоната за комуникация (точно преди отдела за процедури). В съответствие с тези промени операторите Perform, които виждате, ще се променят на изрази за извикване на подпрограми, които ще трябва да посочат зоната за комуникация, която се предава на другата програма.

Като оставим настрана понятието COBOL рекурсия и просто погледнем двете решения, които създадох, кой език бихте избрали, за да разработите свое собствено решение? И двете работят и дават правилните резултати. Но само като погледнем броя на редовете за кодиране, самата логика на COBOL е с 50% по-дълга от решението на Python, а след това трябва да се добавят онези скучни неща.

Победител с технически нокаут...Python!!

Бъдете сигурни, че няма пострадали динозаври при извършването на това сравнение!

Кой е нагоре?

Все още трябва да се работи, за да накарам този сайт да работи правилно в облака и да довърша някои допълнителни функционалности, и ми остават три седмици, за да стигна дотам. Въпреки това съм твърдо решен и съм сигурен, че много скоро ще видите стабилно уеб приложение, обслужващо MLB данни в реално време.

Имах взрив с тази менторска програма и научих много и винаги съм благодарен на ChiPy User Group, нейните членове и най-вече на моя ментор Алън. Благодаря ви, че ме насочихте по страхотен път, от който научих много, и че понякога издържахте на порой от въпроси и малко упоритост. #thankyouAllan!!

Къде да отида оттук? Кой знае, но ще се отворят нови врати и те вече започват да се пропукват. В офиса ми се говори за няколко малки възможности, където мога да се включа и да приложа някои от нещата, които съм научил, и да придобия реален работен опит, използвайки тези по-нови технологии.

Не знам къде този нов път в крайна сметка ще отведе този динозавър, но времената се променят и нещата със сигурност се подобряват!