
От началото на 2018 година заемам позицията на лидер/началник/водещ разработчик в екипа — наречете го както искате, но сутьта е, че изцяло отговарям за един от модулите и за всички разработчици, които работят по него. Тази позиция ми предоставя нов поглед върху процеса на разработка, тъй като участвам в повече проекти и активно участвам в вземането на решения. Наскоро, благодарение на тези две обстоятелства, неочаквано осъзнах колко силно разбирането влияе на кода и на приложението.
Мисълта, която искам да изразя, е, че качеството на кода (и на крайния продукт) е тясно свързано с това, колко добре хората, които проектират и пишат кода, осъзнават какво точно правят.
Възможно е сега да си мислите: „Благодаря, капитан. Разбира се, би било добре да разбираш какво пишеш. В противен случай с такъв успех можеш да наемеш група маймуни, които да удрят на произволни клавиши и да се успокоиш с това“. И сте напълно прави. Съответно приемам за даденост: осъзнавате, че е необходимо да имате обща представа за това, което правите. Това може да се нарече нулево ниво на разбиране и няма да го разглеждаме подробно. Подробно ще разгледаме какво точно трябва да разбирате и как това се отразява на решенията, които взимате всеки ден. Ако бях знаел тези неща предварително, това би ми спестило много време, прекарано напразно, и съмнителен код.
Въпреки че по-долу няма да видите нито един ред код, все пак смятам, че всичко казано тук е от голямо значение за написването на качествен и изразителен код.
Първо ниво на разбиране: Защо не работи?
Разработчиците обикновено достигат до това ниво в най-ранните етапи на кариерата си, понякога дори без никаква помощ от околните — поне според моите наблюдения. Представете си, че получавате репорт за бъг: някаква функция в приложението не работи и трябва да бъде поправена. Как ще действате?
Стандартната схема изглежда така:
- Намиране на фрагмента от кода, който причинява проблема (как точно се прави това е отделна тема, която разглеждам в книгата си за остарял код)
- Внасяне на промени в този фрагмент
- Убедете се, че бъгът е поправен и не са възникнали регресивни грешки.
Сега да се съсредоточим върху втория пункт — внасяне на промени в кода. Има два подхода към този процес. Първият: да се задълбочите в това, което се случва в текущия код, да откриете грешката и да я поправите. Вторият: да действате на сляпо — да добавите, например, +1 в условния оператор или в цикъла, да видите дали функцията заработи в необходимия сценарий, след това да опитате нещо друго и така безкрай.
Правилният подход е първият. Както обяснява в книгата си Code Complete Стив МакКоннъл (между другото, горещо я препоръчвам), всеки път, когато променяме нещо в кода, трябва да можем уверено да предскажем как това ще повлияе на приложението. Цитирам по памет, но ако корекцията на грешката не сработи както очаквате, това трябва да ви накара да се съмнявате в целия си план.
Обобщавайки казаното, за да осъществите качествена корекция на грешка, която няма да влоши качеството на кода, е необходимо да разбирате както структурата на кода, така и източника на конкретния проблем.
Второто ниво на разбиране: Защо работи?
Това ниво се усвоява много по-малко интуитивно от предишното. Аз, като начинаещ разработчик, го научих благодарение на шефа си и след това неведнъж сам обяснявах същността на въпроса на новаците.
Сега нека си представим, че получавате два отчета за грешки наведнъж: в първия става въпрос за сценарий A, във втория — за сценарий B. В двата сценария нещо не е наред. Съответно, първо се заемате с първия бъг. Ръководейки се от принципите, които извлякохме за първото ниво на разбиране, задълбочавате се в кода, свързан с проблема, установявате защо той кара приложението да се държи именно така в сценарий A и внасяте разумни корекции, които дават точно онзи резултат, който сте очаквали. Всичко върви отлично.
След това преминавате към сценарий B. Повтаряте сценария в опит да провокирате грешката, но — изненада! — сега всичко работи както трябва. За да потвърдите предположението си, отменяте промените, направени в процеса на работа по грешка A, и бъг B отново се появява. Вашата корекция е решила и двете проблеми. Успех!
Вие изобщо не сте очаквали това. Придумали сте начин да поправите грешка в сценарий А и нямате представа защо той заработи и за сценарий B. На този етап е много примамливо да решите, че и двете задачи успешно са изпълнени. Това е напълно логично: смисълът беше да се отстранят грешките, нали? Но работата още не е приключила: предстои ви да разберете защо вашите действия поправиха грешката в сценарий B. Защо? Защото вероятно той работи на неправилни принципи и тогава ще трябва да търсите друг изход. Ето няколко примера за такива случаи:
- тъй като решението не е било подбрано целенасочено под грешка B с оглед на всички фактори, вие, вероятно, без да искате, сте счупили функция C.
- не е изключено, че някъде се крие и трета грешка, свързана с тази функция, и вашият бъгфикс свързва коректната работа на системата в сценарий B с нея. В момента всичко изглежда добре, но в един прекрасен ден този трети бъг ще бъде забелязан и коригиран. Тогава в сценарий B отново ще възникне грешка и е добре, ако е само там.
Всичко това внася в кода хаос и рано или късно ще се стовари върху вас — вероятно в най-неподходящия момент. Ще трябва да съберете волята си, за да накарате себе си да отделите време за разбирането на това, защо всичко изглежда да работи, но си струва.
Трето ниво на разбиране: Защо работи?
Наскоро осъзнах точно това ниво и вероятно именно то би ми донесло най-много предимства, ако бях стигнал до това по-рано.
За да бъде по-понятно, нека разгледаме пример: вашият модул трябва да бъде съвместим с функция X. Не сте много запознати с функция X, но ви казаха, че за съвместимост с нея трябва да използвате фреймворк F. Други модули, които се интегрират с X, работят именно с него.
Вашият код от първия ден на съществуването си не е имал нищо общо с фреймворка F, затова внедряването му няма да е толкова лесно. Това ще доведе до сериозни последствия за някои компоненти на модула. Въпреки това, вие се впускате в разработка: седмици наред пишете код, тествате, пускате пробни версии, получавате обратна връзка, поправяте регресионни грешки, откривате непредвидени усложнения, не спазвате първоначално уговорените срокове, пишете още известно количество код, тествате, получавате обратна връзка, поправяте регресионни грешки — всичко това, за да внедрите фреймворка F.
И в някой момент изведнъж осъзнавате — или може би чувате от някого — че фреймворкът F може изобщо да не ви даде съвместимост с функцията X. Може би всичките тези време и усилия са били вложени напълно не в правилната посока.
Нещо подобно веднъж се случи по време на работа по проект, за който аз отговарях. Защо стана така? Защото не разбирах добре каква е същността на функцията X и как тя е свързана с фреймворка F. Как трябваше да постъпя? Да попитам човека, който поставя задачата за разработка, да обясни ясно как предвиденият план на действие води до желания резултат, вместо просто да повтарям това, което е правено за други модули, или да вярвам на думата, че това е необходимо за работата на функцията X.
Опитът от този проект ме научи да отказвам да започвам процеса на разработка, докато нямаме ясно разбиране защо ни се поръчват определени действия. Да отказвам директно. Когато получаваш задача, първият импулс е незабавно да се заемеш с нея, за да не губиш времето си. Но политиката „замразяваме проекта, докато не разберем всички подробности“ може да намали времето, прекарано на опити, с порядъци.
Дори и да ви оказват натиск, да ви принуждават да започнете работа, макар че не разбирате защо — съпротивлявайте се. Първо разберете с каква цел ви поставят такава задача и решете дали това е правилният път към целта. Наложи се да науча всичко това на горчив опит — надявам се, че моят пример ще улесни живота на тези, които четат.
Четвърто ниво на разбиране: ???
В програмирането винаги има какво да се научи и смятам, че едва засегнах най-основните аспекти на темата за разбирането. Какви още нива на разбиране открихте през годините работа с код? Какви решения взехте, които положително повлияха на качеството на кода и приложението? Какви решения се оказаха погрешни и ви дадоха ценен урок? Споделете опит в коментарите.
Източник: habr.com
