Какво изпитах при рефакторинг на JavaScript проект, разработен от нови програмисти.

Миналата година ми беше представен проект vue с прилични размери, изграден от предимно нови разработчици, който ми беше възложено да преработя.

Първо трябваше да разбера какво всъщност прави приложението. Завъртях нов екземпляр и бях посрещнат от наситеночервена конзола за разработчици.

о да Все още не знаем откъде идват тези грешки, но работи!

И свърши работа, някак си, което беше доста невероятно, честно казано. Но не трябваше да чакам твърде дълго, за да се появят грешки и забавяния.

GIT

Според мен първата стъпка беше въвеждането на добър контрол на версиите. Не просто исках да преработя самото приложение, но го видях по-скоро като преработване на проекта като цяло. Голяма част от това ще изглежда основно знание за много разработчици. Но ако започнете на чисто, изглежда, че забравяте или не ви пука за тези неща. Просто искате да започнете да програмирате и да свършите нещата. Всички сме го чували преди:

„Преди дори да започнете да пишете код, помислете какъв проблем се опитвате да разрешите и как смятате, че можете да го постигнете“.

Много нови разработчици не приемат този съвет достатъчно сериозно или забравят, че този съвет трябва да се има предвид и за неща, които не включват действително кодиране. Като управление на проекти.

GIT вече беше в употреба, което много приветствах. Начинът, по който го използваха обаче, не беше идеален. Всеки просто би се натиснал до един клон. Понякога те биха създали нов клон, за да внедрят определена версия. Често поправките към този нов клон не се обединяват с оригиналния клон за разработка, оставяйки след себе си повтарящи се грешки, когато дойде време да се разклони нова версия. Друг проблем беше форматирането. Всеки имаше различни конфигурирани правила за форматиране. Това би довело до масивни натискания, само защото един разработчик ще преобразува раздели в интервали, ще добави точки и запетая и ще използва Camel Case. Само за следващия разработчик да генерира още един огромен тласък, обръщайки тези промени.

Изводи за вкъщи:

  • Изберете стратегия за разклоняване и се придържайте към нея.
  • Изберете еднообразно форматиране.
  • Проверете ангажиментите си, преди да ги ангажирате.
  • Използване на заявки за сливане.

Не наистина! Ако очаквате приложението ви да се развива, ако работите с други хора или дори ако планирате да поддържате приложението си за по-дълъг период от време: Инвестирайте време в добро управление на версиите!

След кратък семинар решихме стратегия за разклоняване, конфигурирах eslint и prettier да използват еднообразно форматиране и въведохме заявки за сливане. Добре нали? Не точно. Въпреки че накратко споменах пребазирането, не наблегнах достатъчно върху него. След няколко месеца нова функция беше готова за обединяване. През тези няколко месеца много промени се случиха в първоначалния клон, включително преструктуриране. Можете да си представите как е изглеждала заявката за сливане. Беше огромно. Сливането отне много време и дори достигнахме момент, в който единствената възможна опция беше да го направим отново, защото загубихме общия преглед.

Ако клонът ви за функции остарее много, пребазирането е добър инструмент за избягване на масивни конфликти при сливане

Според моя опит все пак трябва да внимавате с пребазирането. Обединяването е предпочитаният от мен начин за въвеждане на нови функции, но когато имате такава огромна реконструкция на вашата кодова база, конфликтите при сливане просто стават твърде много за справяне, така че повторното базиране на по-малки промени от време на време е по-лесно за справяне.

Не може да се прочете свойството „x“ на undefined

Следваща стъпка: Всъщност разглеждане на самия код и въвеждане на Typescript. Защо Typescript?

Използването на динамично писане в JavaScript не означава, че можете просто да забравите за типовете! Все още трябва да се грижите за типовете. Вие трябва да знаете какви свойства има обектът, който току-що сте предали на функция. Вие трябва да знаете дали „числото“, с което работите, всъщност е число или представяне на низ. Но липсата на проверка на типове, която да се оплаква от него, го прави лесно да се забрави. Удобно е просто да добавите свойство към някакъв обект надолу по линията. Липсата на добре дефинирани типове прави много по-трудно влизането в кодовата база.

Често срещах дефиниции на обекти върху функция. Бихте предположили, че това описва типа, но никога не можете да сте сигурни. Нищо не пречи на разработчика просто да добави нови свойства по-късно. Комбинирайте това без заявки за сливане и прегледи на кода, защото кодът „работи“ и оставате с кодова база, която е неразумно трудна за следване.

Друг повтарящ се проблем беше „числата“ и кастинга. Никога не знаете дали в момента работите с число или низово представяне на число. Това би довело до излишни проверки, грешки „не е функция“ или в най-лошия случай грешно прехвърляне на типа.

Представете си, че работите с това, което предполагате, че е число, и добавяте друга променлива, която също приемате, че е число. Ако 5 + 9 е равно на 59, знаете, че трябва да започнете да се интересувате от типовете данни.

Нулева проверка. На пръв поглед образцово. Но отново, непознаването точно на типа, с който работите, съчетано с много сложни преобразувания на типове, не е толкова лесно за начинаещи програмисти. Нулевата проверка на свойство на обект, който не съществува с ‘!== null’ ви създава проблеми! Просто използвайте самото свойство вътре в условието if. Той ще създаде ново булево значение от свойството, което от своя страна връща верността на споменатия тип според документацията.

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

Можех просто да използвам typescript и vue, но намерих vue-property-decorator за много полезен. Въпреки че не съм голям фен на използването на компоненти на стила на класа в JavaScript, това направи прехода по-плавен. Класическото ООП изглеждаше много по-лесно за новите разработчици от наследяването на прототип на JavaScript.

За да разширя този стил, избирам vuex-module-decorators за vuex модулите.

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

Конфигурация на проекта

Какво всъщност ви е необходимо за прехода към TypeScript? Оказва се, че не е толкова много.

  • tsconfig.json: Конфигурационният файл за вашия TypeScript компилатор. Документацията на Vue ви покрива тук.
  • webpack: Отново, ако просто следвате документацията за това как да използвате typescript с webpack и сте готови.
  • @type/mypackage: Повечето пакети вече експортират дефиниции на типове. Можете лесно да ги инсталирате с npm/yarn.
  • vue-shims.d.ts: Ако използвате единични файлови компоненти, трябва да кажете на компилатора как да обработва тези файлове.

Компоненти на Vue

Конвертирането на Vue компоненти беше доста лесно. Вместо да експортирате функция, вие експортирате клас, който се разширява върху класа vue, предоставен от vue-property-decoratos. Членовете данни представляват състоянието, а функционалните членове - действията.

Следваща стъпка типовете анотиране. Открих, че е по-лесно да дефинирам един голям интерфейс и да оставя класа да внедри споменатия интерфейс, вместо да дефинира типове за всеки член от данни.

Vuex модули

Точно като компонентите, можете да експортирате клас, който разширява vuex модул и създава анотации.

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

Огромно количество недефинирани употреби на свойства, грешно преобразуване на типове и дори излишен код бяха коригирани чрез просто дефиниране на типове.

Това спестява много време. Представете си времето, което губите при отстраняване на грешки при недефинирани и нулеви проблеми. Комбинирайте това с нечетлива кодова база и ще се забавлявате!

API интерфейс

За да завършим рефакторинга, създадохме дефиниции на типове за всяко извикване на API. Той включваше тип отговор, който сам по себе си съдържаше общо свойство на данните. Всеки отговор ще върне обект от този тип и ще запълни генеричния код с обект, описан отново от неговия собствен тип. Същото важи и за заявката.

Като цяло преработването на кода отне няколко седмици. Заслужаваше ли си? Напълно! Количеството грешки беше намалено с огромно количество, качеството на кода се повиши драстично и добавките към кода бяха много по-лесни. Чувствах, че компилаторът на TypeScript ще ме отведе до нещата, които трябваше да бъдат преработени, вместо да търся безцелно.