Не згаджайцеся распрацоўваць тое, чаго не разумееце

Не згаджайцеся распрацоўваць тое, чаго не разумееце

З пачатку 2018 года я займаю пасаду ліда/начальніка/вядучага распрацоўшчыка ў камандзе — называйце гэта як хочаце, але сутнасць у тым, што я цалкам адказваю за адзін з модуляў і за ўсіх распрацоўшчыкаў, якія над ім працуюць. Гэтая пазіцыя адкрывае мне новы погляд на працэс распрацоўкі, бо я задзейнічаны ў большай колькасці праектаў і больш актыўна ўдзельнічаю ў прыняцці рашэнняў. Нядаўна, дзякуючы гэтым двум абставінам, я нечакана ўсвядоміў, як моцна мера разумення ўплывае на код і на дадатак.

Думка, якую я хачу выказаць, зводзіцца да таго, што якасць кода (і канчатковага прадукта) цесна звязана з тым, наколькі людзі, якія займаюцца праектаваннем і пішуць код, усведамляюць, што менавіта яны робяць.

Вы, магчыма, зараз думаеце: «Дзякуй, кэп. Вядома, нядрэнна б разумець, што ўвогуле пішаш. Інакш з тым жа поспехам можна наняць групу малпаў, каб яны малацілі па адвольных клавішах, і на гэтым супакоіцца». І вы маеце рацыю. Адпаведна, я прымаю як дадзенасць: вы ўсведамляеце, што мець агульнае ўяўленне аб тым, што робіш, неабходна. Гэта можна назваць нулявым узроўнем разумення, і яго мы не будзем разбіраць падрабязна. Падрабязна мы будзем разбіраць, што менавіта трэба разумець і як гэта адбіваецца на рашэннях, якія вы прымаеце кожны дзень. Калі б я ведаў гэтыя рэчы загадзя, гэта пазбавіла б мяне ад масы выдаткаванага марна часу і сумнеўнага кода.

Хоць ніжэй вы ніводнага радка кода не ўбачыце, я ўсёткі лічу, што ўсё тут сказанае мае вялікае значэнне для напісання якаснага, выразнага кода.

Першы ўзровень разумення: Чаму яно не працуе?

Да гэтага ўзроўню распрацоўшчыкі звычайна прыходзяць на самых ранніх этапах сваёй кар'еры, часам нават без якой-небудзь дапамогі з боку навакольных – прынамсі, па маіх назіраннях. Уявіце, што вы атрымалі багрэпорт: нейкая функцыя ў дадатку не працуе, яе трэба паправіць. Як вы будзеце дзейнічаць?

Стандартная схема выглядае так:

  1. Знайсці фрагмент кода, які выклікае праблему (як гэта робіцца - асобная тэма, яе я раскрываю ў сваёй кнізе аб састарэлым кодзе)
  2. Унесці ў гэты фрагмент змены
  3. Пераканацца, што баг выпраўлены і рэгрэсіўных памылак не ўзнікла

Зараз засяродзімся на другім пункце - унясенні змяненняў у код. Ёсць два падыходы да гэтага працэсу. Першы: углыбіцца ў тое, што менавіта адбываецца ў бягучым кодзе, выявіць памылку і выправіць яе. Другі: прасоўвацца навобмацак - дадаць, дапусцім, +1 ва ўмоўны аператар або цыкл, паглядзець, ці не зарабіла гэтага функцыя ў патрэбным сцэнары, потым яшчэ што-небудзь паспрабаваць і так да бясконцасці.

Правільным з'яўляецца першы падыход. Як тлумачыць у сваёй кнізе Code Complete Стыў МакКонэл (дарэчы, вельмі яе рэкамендую), кожны раз, калі мы нешта мяняем у кодзе, мы павінны быць у стане з упэўненасцю прадказаць, як гэта паўплывае на дадатак. Прыводжу цытату па памяці, але калі багфікс спрацоўвае не так, як вы чакалі, вас павінна гэта моцна насцярожыць, вы павінны паставіць пад пытанне ўвесь свой план дзеянняў.

Абагульняючы сказанае, каб выканаць дыхтоўны багфікс, які не пагоршыць якасць кода, трэба разумець і ўсю структуру кода, і крыніца пэўнай праблемы.

Другі ўзровень разумення: Чаму яно працуе?

Гэты ўзровень спасцігаецца значна менш інтуітыўна, чым папярэдні. Я, будучы яшчэ пачаткоўцам распрацоўшчыкам, засвоіў яго дзякуючы начальніку, а пасля неаднаразова сам тлумачыў сутнасць справы пачаткоўцам.

На гэты раз давайце ўявім, што вам паступіла адразу два багрэпорты: у першым гаворка ідзе аб сцэнары A, у другім - аб сцэнары B. У абодвух сцэнарах адбываецца нешта не тое. Адпаведна, вы прымаецеся спачатку за першы баг. Кіруючыся прынцыпамі, якія мы вывелі для першага ўзроўню разумення, вы як след унікаеце ў код, які мае дачыненне да праблемы, высвятляеце, чаму ён прымушае прыкладанне паводзіць сябе менавіта так у сцэнары А, і ўносіце разумныя карэктывы, якія даюць менавіта той вынік, якога вы чакалі. Усё ідзе выдатна.

Затым вы пераходзіце да сцэнара B. Вы паўтараеце сцэнар у спробе справакаваць памылку, але - сюрпрыз! - цяпер усё працуе як трэба. Каб пацвердзіць сваю здагадку, вы адмяняеце змены, занесеныя падчас прац над памылкай А, і баг B зноў вяртаецца. Ваш багфікс вырашыў абедзве праблемы. Пашанцавала!

Вы на гэта зусім не разлічвалі. Вы прыдумалі спосаб выправіць памылку ў сцэнары А і паняцця не маеце, чаму ён спрацаваў і для сцэнара B. На гэтым этапе вельмі вялікая спакуса вырашыць, што абедзве задачы шчасна выкананы. Гэта цалкам лагічна: сэнс бо быў у тым, каб ухіліць памылкі, няўжо не? Але праца яшчэ не скончана: вам яшчэ трэба будзе разабрацца, чаму вашыя дзеянні выправілі памылку ў сцэнары B. Навошта? Затым, што ён, магчыма, працуе на няслушных прынцыпах, і тады вам трэба будзе шукаць іншае выйсце. Вось пара прыкладаў такіх выпадкаў:

  • бо рашэнне не падбіралася прыцэльна пад памылку B з улікам усіх фактараў, вы, магчыма, самі таго не падазраючы зламалі функцыю C.
  • не выключана, што дзесьці стаіўся яшчэ і трэці баг, злучаны з той жа функцыяй, і ваш багфікс завязвае карэктную працу сістэмы ў сцэнары B на ім. Цяпер усё выглядае добра, але ў адзін цудоўны дзень гэты трэці баг заўважаць і выправяць. Тады ў сцэнары B зноў узнікне памылка, і добра, калі толькі там.

Усё гэта ўносіць у код хаатычнасць і калі-небудзь зваліцца вам на галаву - хутчэй за ўсё, у самы непадыходны момант. Прыйдзецца сабраць волю ў кулак, каб прымусіць сябе марнаваць час на разуменне таго, чаму ўсё з выгляду працуе, але яно таго варта.

Трэці ўзровень разумення: Навошта яно працуе?

Маё нядаўняе азарэнне звязана якраз з гэтым узроўнем, і, напэўна, менавіта ён даў бы мне больш за ўсё пераваг, калі б я прыйшоў да гэтай думкі раней.

Каб было больш зразумела, разбяром на прыкладзе: ваш модуль трэба зрабіць сумяшчальным з функцыяй X. Вы не асабліва блізка знаёмыя з функцыяй X, але вам сказалі, што для сумяшчальнасці з ёй трэба выкарыстоўваць фрэймворк F. Іншыя модулі, якія інтэгруюцца з X, працуюць менавіта з ім.

Ваш код з першага дня свайго жыцця наогул не датыкаўся з фрэймворкам F, таму ўкараніць яго будзе не вось так проста. Гэта пацягне сур'ёзныя наступствы для некаторых складнікаў модуля. Тым не менш, вы з галавой сыходзьце ў распрацоўку: тыднямі пішаце код, тэстуеце, выкочваеце пілотныя версіі, атрымліваеце фідбэк, выпраўляеце рэгрэсійныя памылкі, выяўляеце непрадбачаныя ўскладненні, не ўкладваецеся ў першапачаткова абумоўленыя тэрміны, пішаце яшчэ колькі кода, тэстуеце сувязь, выпраўляеце рэгрэсійныя памылкі - усё гэта дзеля таго, каб укараніць фрэймворк F.

І ў нейкі момант вы раптам усведамляеце - ці, можа быць, чуеце ад кагосьці - што, можа быць, фрэймворк F зусім і не дасць вам сумяшчальнасці з функцыяй X. Можа быць, увесь гэты час і сілы былі прыкладзены зусім не да таго.

Нешта падобнае аднойчы адбылося падчас працы над праектам, за які я адказваў. Чаму так атрымалася? Таму што я дрэнна разумеў, у чым сутнасць функцыі X і як яна звязана з фрэймворкам F. Як мне трэба было паступіць? Папытаць чалавека, які ставіць задачу на распрацоўку, даходліва растлумачыць, як вызначаны план дзеянняў прыводзіць да жаданага зыходу, замест таго каб проста паўтараць тое, што рабілася для іншых модуляў, ці верыць на слова, што так трэба для працы функцыі X.

Досвед гэтага праекту навучыў мяне адмаўляцца пачынаць працэс распрацоўкі, пакуль у нас няма яснага разумення, чаму нас просяць выканаць тыя ці іншыя дзеянні. Адмаўляцца прамым тэкстам. Калі атрымліваеш задачу, першы імпульс - неадкладна за яе ўзяцца, каб не губляць дарма часу. Але палітыка «замарожваем праект, пакуль не ўвойдзем ва ўсе прыватнасці» можа скараціць марнавы час на цэлыя парадкі.

Нават калі на вас спрабуюць націснуць, прымусіць пачаць працу, хоць вы не разумееце, чым гэта абгрунтавана - супраціўляйцеся. Спачатку разбярыцеся, з якой мэтай вам ставяць такую ​​задачу, і вырашыце, ці дакладны гэта шлях да мэты. Мне прыйшлося ўсё гэта даведацца на горкім досведзе - спадзяюся, тым, хто гэта чытае, мой прыклад палегчыць жыццё.

Чацвёрты ўзровень разумення: ???

У праграмаванні заўсёды ёсць чаму павучыцца, і мяркую, я толькі закрануў самыя верхнія пласты тэмы разумення. Якія яшчэ ўзроўні разумення вы выявілі за гады працы з кодам? Якія прымалі рашэнні, якія добра адбіліся на якасці кода і дадатку? Якія рашэнні аказаліся памылковымі і далі вам каштоўны ўрок? Дзяліцеся вопытам у каментарах.

Крыніца: habr.com

Дадаць каментар