Це переклад статті від Джозефа М. Ньюкомера - http://www.flounder.com/bricks.htm про те як на його думку виглядає процесс навчання програмістів. Це все ще актуальні спостереження, навіть 20 років по тому

Ступінь з цегляної науки

Дехто з нас, хто знаходяться у Реальному Світі, вражені — якщо взагалі можна вжити це слово — якістю яскравих молодих студентів бакалаврату з комп’ютерних наук. У своїй викладацькій практиці я стикаюся з людьми, які фактично є функціонально неграмотними у своїй професії. Що має знати випускник? Безумовно, як створювати й обробляти зв’язані списки, як встановлювати й скидати біти у значеннях. Вони повинні знати синтаксис мов програмування, у яких вони заявляють про свою компетентність. Я викладаю курси, де «знання мови С» є попередньою вимогою. У деяких випадках я цілком переконаний, що майбутні студенти тлумачать це як: «Можу написати назву мови з лише незначними помилками».

Один студент застряг на задачі написання фрагменту коду. Я сказав: «Ну, в такому разі, тобі потрібно написати щось на кшталт ‘if condition then …’, і виконувати обчислення тільки якщо умова дійсна». Це здавалося очевидним. За кілька хвилин я заглянув через його плече, і він набрав у програмі на C

if condition then

і намагався вирішити, що написати далі!

Одного разу я мав повний клас (ну, 8 осіб) щойно випущених бакалаврів наук з якогось університету у Флориді, неподалік Орландо, які протягом чотирьох годин виконання вправи з паралельного чергування потоків (parallel-thread queuing) намагалися зрозуміти, як написати зв’язаний список! Після того як у вівторок було змарновано дві години, я пішов до менеджера з навчання і сказав: «У вас тут серйозна проблема». Вона раніше працювала програмістом і була вражена. Тож вона запропонувала мені просто ввести код і дати його їм. Я так і зробив. Я написав функцію

void AddToList(Item * p)
   {
    if(head == NULL)
      head = tail = p;
    else
      {
       tail->next = p;
       tail = p;
      }
    }

Один студент мав серйозні проблеми з цим. Код не компілювався. Причиною було те, що я заздалегідь надав їм прототип функції

void AddToList(Item * data)
   {
    //... ваш код тут
   }

Звісно, ви, мабуть, уже здогадалися, що сталося: він скопіював текст безпосередньо з мого прикладу й не міг зрозуміти, чому символ p є невизначеним.

Безумовно найгіршою була жінка, яка працювала в Інституті програмної інженерії. Вона була щойно найнята після закінчення Університету Карнегі-Меллона — одного з найрейтинговіших навчальних закладів з комп’ютерних наук у країні, а можливо, й у світі. Вона написала

printf("The value is %d," value);

і компілятор видавав їй синтаксичну помилку. Я помітив її (а ви можете? Погляньте самі…) за кілька секунд.

Тож я сказав їй: «Ти переставила кому і лапку», і пішов далі. За кілька хвилин, проходячи повз, я почув, як вона каже, що код усе ще не компілюється. Я знову побачив ту саму помилку й сказав: «Кома має стояти за межами лапки». Вона подивилася на мене й з абсолютною щирістю сказала: «Але ж кома завжди ставиться всередині лапок!». Я почав пояснювати, що ні, у цьому випадку кома — це роздільник параметрів, тому вона має стояти поза лапками, і вона перебила мене, наполягаючи, що код синтаксично правильний. Усі ж знають, що кома має бути всередині лапок! Її вчителі англійської знижували оцінки, коли вона ставила кому після лапки!

Я кинув якесь зауваження про те, що вона явно занадто дурна, щоб знати, як дихати, і що я точно не збираюся витрачати свій час на пояснення синтаксису C випускниці комп’ютерних наук з CMU. Я зробив усе можливе, щоб її усунули з будь-якого місця, де вона могла б мати справу з комп’ютером, але не знайшлося нікого з достатнім смаком або розумом, щоб позбутися її. Проте мені вдалося уникати її до кінця мого перебування там. Одного разу вона написала програму, яку ми всі мали використовувати; вона була настільки жахливою, що була б соромом для мого племінника, коли йому було 12 — а він програмував уже два роки на той момент (він закінчив навчання у 2003 році зі ступенем у галузі комп’ютерної графіки).

Пітер Віскарола у своїй колонці “Peter Pontificates” в інформаційному бюлетені OSR поділяє подібні спостереження. Він розповідає про співбесіди з потенційними кандидатами, які мали два семестри операційних систем і не могли пояснити, що таке синхронізація. Які мали два семестри операційних систем і за весь цей час не написали жодного рядка коду. Я знаю людину в Microsoft, яка перевіряла кандидатів завданням: «Вставте цей елемент у зв’язаний список у відсортованому порядку». Із 27 кандидатів лише одна, жінка, яка працювала над своєю докторською дисертацією, змогла це зробити взагалі.

Я принаймні приблизно розумію, у чому тут проблема.

Спеціальність «Цегляна наука»

Уявіть собі, що в університеті існує спеціальність «Цегляна наука». Як би вона виглядала, якби була побудована за зразком більшості програм з комп’ютерних наук?

На першому курсі ми навчаємо студентів про цеглу. Види цегли. Розміри цегли. Призначення цегли. Звичайна цегла, глазурована цегла, вулична цегла, тротуарна цегла, вогнетривка цегла. Кожен іспит перевіряє їхні знання про конкретні види цегли та їхнє застосування.

На другому курсі ми знайомимо їх з Теорією Цегли. Як виготовляють цеглу. Що входить до складу суміші. Вплив домішок у цеглі — як негативний (дефектна цегла), так і позитивний (забарвлення). Ми викладаємо їм хімію цегли. Правильні температури випалу для різних видів цегли. Вони вчаться аналізувати характеристики цегли (міцність на злам, водопроникність, стійкість та інші аспекти Аналізу Цегли). Вони нарешті розуміють, чому деякі цеглини мають три маленькі отвори (про їхнє існування вони дізналися ще на першому курсі, але тоді не знали, навіщо вони потрібні).

На третьому курсі ми пояснюємо, як розчин з’єднує цеглини разом. Оскільки тепер у них є більше базових знань, протягом двох семестрів ми починаємо з основної теорії розчину й переходимо до оптимальних сумішей розчину для різних потреб. Вони вивчають час твердіння. Вони дізнаються про комбінації цегли й розчину. Вони вивчають розшивку швів і чому вона необхідна. Вони знають, як визначити міцність зчеплення, вимірюючи силу, необхідну для розділення двох з’єднаних розчином цеглин.

На четвертому курсі ми вводимо їх у системи. Ми обговорюємо вартість розгортання цегельно-розчинних систем у полі, включаючи встановлення та обслуговування, а також довгострокові проблеми, такі як стійкість системи до погодних умов, солі та інших навантажень. І у нас є курсовий проєкт. Кожна група студентів має побудувати стіну висотою в три блоки та шириною в шість блоків, використовуючи цеглу та розчин за власним вибором, і пояснити, чому вони зробили саме такий вибір.

Вони випускаються. У них ступінь бакалавра наук у галузі Цегляної науки.

Їхнє перше завдання: «Побудуйте декоративну цегляну стіну».

На цьому етапі вони усвідомлюють, або принаймні мають усвідомити, наскільки мало вони насправді вивчили. Вони ніколи не будували нічого більшого за конструкцію з 18 цеглин. Вони не знають того прийому, яким користуються всі мулярі — натягнути шнур, щоб цеглини були вирівняні вздовж 30-метрової стіни. Вони точно не мають уявлення про сучасний підхід — лазер, що «малює» лінію вздовж ряду цеглин. Вони не знають, як справлятися з вітровими навантаженнями на високу стіну. Їм ніхто не розповідав про фундамент чи про глибину промерзання ґрунту. Вони навіть не знають, як користуватися спеціальним молотком, яким розколюють цеглину навпіл. І вони не мають жодного уявлення про естетику, тож не розуміють, що насправді означає «декоративна».

У будівельних спеціальностях навчання — це лише підготовка до «учнівства». Воно триває кілька років під наглядом досвідчених мулярів. Лише коли учень демонструє певний рівень майстерності, його підвищують з «учня» до «майстра-подорожнього» (або, щоб бути політкоректним, «майстра-подорожньої особи»). Коли досягається високий рівень експертизи, особа стає «майстром». У програмуванні дуже часто молодих спеціалістів сприймають як досвідчених і кидають напризволяще. Я витратив багато часу на наставництво молодих фахівців, і це абсолютно необхідна частина професійної відповідальності. Але перед тим, як їх варто наставляти, вони мають бути функціонально грамотними. За рідкісними винятками (як-от нова працівниця з SEI), це не люди з труднощами у навчанні — це люди з дипломами бакалаврів, часто з провідних університетів. Якщо вони не знають основ своєї професії, то це або їхня провина, або провина програм, які вони пройшли. Від муляра очікується, що він фізично здатен виконувати роботу, уміє додавати й віднімати, користуватись лінійкою і знає, який кінець кельми тримати в руці, а який — занурювати в розчин. Та нова співробітниця з SEI, у порівнянні зі своєю заявленою професією, була неспроможна навіть впізнати цеглину. Усе інше було складнішим за це.

Коли я розповів цю історію своєму другові Кевіну Нолішу, старшому інженерові в компанії Marconi, він сказав: «Ні, єдина відмінність між твоєю історією та реальністю — це те, що насправді бригадир швидше обійме новачка за плечі, вкаже на купу дощок і скаже: “Іди й побудуй”».

А як щодо інших шкіл, які мають більш «прикладну» навчальну програму? Все просто. Програма виглядає так:

На першому курсі їм розповідають про тротуарну цеглу. Цілий рік присвячений тому, як використовувати тротуарну цеглу.

На другому курсі вони вивчають, як будувати ґанки з тротуарної цегли.

На третьому курсі вони дізнаються, як робити тротуари з тротуарної цегли.

На четвертому курсі вони вчаться створювати під’їзні доріжки з тротуарної цегли. Це дуже складно, бо потрібно враховувати навантаження від важких об’єктів.

А після випуску ситуація та сама.

Це як ті школи, що пропонують спеціальність з «комп’ютерних наук», де все програмування протягом чотирьох років виконується лише однією мовою — Pascal, C, FORTRAN, BASIC, Visual Basic, Java, COBOL або будь-якою іншою (мова змінюється відповідно до чергової модної тенденції; проблеми залишаються). Якщо ви запитаєте в таких студентів, що таке «скінчений автомат», вони подивляться на вас порожнім поглядом. Скажіть їм, що їхній алгоритм має складність n² — вони застигнуть. Вони не впізнають NP-складної задачі чи нерозв’язної проблеми, навіть якщо та вкусить їх за щиколотку. Вони, ймовірно, ніколи не брали участі в командному проєкті або не писали програму, більшу за 1000 рядків. А може, й не настільки велику.

Самоучки-мулярі йдуть до найближчого магазину будматеріалів, купують мішок чи два якогось розчину, багажник або два цегли, яку знайшли за знижкою, і йдуть додому будувати стіну.

Кращі з них купують добру інструкційну книжку про мурування. Більшість читає її. Дехто намагається зрозуміти. Кілька — справді розуміють.

Жоден із цих людей, у жодному з перелічених сценаріїв, не стикається з професійним мулярем.

Коли стіна валиться або деформується вже першої весни після зведення, викликають таких людей, як я, щоб перебудувати її.

Інколи люди скаржаться, коли я саркастично відгукуюсь про напіввипадкові купи цегли, що більш-менш утримуються разом чимось, схожим на розчин.

Реальна історія: у нас був кандидат на роботу, який здавався трохи нижче порогу. Мій колега запитав його: «Яка найбільша програма, яку ви коли-небудь писали?» Він з гордістю відповів: «800 рядків!» Того ж вікенду я написав 2500 рядків коду. І це з урахуванням кількох годин перерви на концерт симфонічної музики. Я зазвичай кажу про «тривіальні програми на 10 000 рядків», і це, як правило, шокує будь-яких студентів, з якими я спілкуюсь. Більшість із них вважає програму на 5000 рядків масивною роботою. Мої ж серйозні проєкти зазвичай складають близько 100 000 рядків; деякі сягають 250 000. Якось я написав 100 000 рядків коду за рік. Мій колега, який також вів бізнесову частину компанії, написав «лише» 70 000. На момент, коли мене найняли в лютому, програма налічувала майже 80 000 рядків. У березні наступного року вона сягала 238 000 (числа не зовсім збігаються, бо ми також викинули кілька модулів. Ми з ним працювали над майже повністю незалежними частинами коду, тож легко було визначити, хто що написав). Він був повністю самоучкою в програмуванні, і писав один із найелегантніших кодів, які я коли-небудь бачив. Він був ремісником, що програмував (і справді був ремісником — займався художньою столяркою, перш ніж повернувся до навчання за спеціальністю «комп’ютерні науки»).

За п’ять днів до написання цього есе я створив 4470 рядків вихідного коду. Мій оплачуваний час становив 31 годину. Це 144 рядки на годину (за японським стандартом продуктивності програмування), не рахуючи 28-сторінкового довідника, який я також написав у цей період і в межах тієї ж оплати. Японський стандарт дозволяє рахувати рядки з бібліотек, які можна повторно використовувати. Якщо відняти 1038 рядків існуючої бібліотеки, яку я використав, залишиться 3423 рядки, або 110 рядків на годину фактичної продуктивності. Це повільніше за мій звичний темп, бо це мав бути вишуканий «референтний код», який компілюється принаймні на трьох різних платформах (NDA забороняє мені називати дві з них), і я дуже старався. Ми також зробили як мінімум одну нетривіальну переробку, яка передбачала викидання кількох сотень рядків, аби спростити завдання, щойно ми сформулювали правильну модель. Колись галузевий стандарт продуктивності складав 5 рядків за годину, а «суперпрограміст» міг написати 20 рядків на годину готового коду. І це без урахування повного тестування та документації.

Я працював над проєктами, у яких брали участь 20–30 програмістів, і ми створювали робочий код, яким мали користуватися інші люди. Поняття такі як модульне тестування, система фіксації та повернення змін, цілісність складання тощо — тут критично важливі.

Це обов’язок старших спеціалістів — навчати молодших. А обов’язок університетів і коледжів — підготувати їх до цього навчання. Це означає навчити їх міркувати про програми й навчитися вчитися. Усе інше — лише синтаксис.

Дайте мені програміста, який уміє міркувати про програми — і я зможу навчити його синтаксису будь-якої мови за короткий час. Мені не доведеться пояснювати, чому певна конструкція має сенс — тільки як її реалізувати у вибраній мові чи середовищі. І я можу навчити підтримувати модульність, абстракцію та створювати добре структуровані програми без необхідності пояснювати, чому це хороша ідея. Найскладніша проблема — навчити людей мислити про програмування як про мистецтво.

Нещодавно мене попросили прокоментувати фрагмент коду для Windows. Це, мабуть, був один із найгірше написаних фрагментів коду, які я коли-небудь бачив. Він не мав сенсу в жодній мові, на жодній платформі, в жодному середовищі. Я відповів, що перестав його читати після чотирьох рядків, бо було зрозуміло, що код не підлягає порятунку. Усе інше вже не мало значення. Через кілька днів з’явився ще гірший приклад — від того ж програміста. Хтось запитав, як переконати менеджера, що автор цього коду просто займає місце. Я прокоментував, що все ще гірше. Людина, яка просто займає місце, не має чистої продуктивності. Цей програміст був надзвичайно небезпечним, бо не просто займав місце — він активно завдавав шкоди. Людина настільки некомпетентна, що єдиною можливою послугою для суспільства було б тримати її якомога далі від будь-якого компілятора. «Як такий код взагалі міг пройти рев’ю?» — запитав я. А тоді додав: «У вас же проводяться рев’ю коду, правда?», хоча прекрасно знав, що відповідь — «Ні». Жодна здорова організація не пропустила б такий код. Недоліки цього програміста стали б очевидними майже миттєво. Було б зрозуміло, що є лише два варіанти: або навчити цю людину, або позбутися її.

Рев’ю коду — важлива практика. Не існує коду, який не можна було б покращити за допомогою рев’ю. І я говорю також про свій власний код. Мені доводилося проводити рев’ю для клієнтів, коли я готував їхніх програмістів до передачі проєкту. Я знаходжу баги. Я знаходжу погано реалізовані алгоритми. Мій код завжди покращується внаслідок рев’ю, навіть якщо він і так був дуже добрим. Ці покращення зазвичай незначні, але це все одно покращення. І програмісти, яких я навчаю, завжди дізнаються щось нове та корисне.

Жоден притомний будівельний майстер не доручив би новоспеченому випускнику з «Цегляної науки» завдання збудувати декоративну цегляну стіну, не переконавшись, що та людина пройшла належну підготовку, і не контролював би її роботу. І навряд чи був би ввічливим при справді дурних проєктних рішеннях («Що ти маєш на увазі під “Що таке фундамент?” Та де ж ти, $%#!, навчився будувати стіни?!»). Проте менеджери з програмування регулярно вважають, що їхні нові випускники комп’ютерних наук здатні програмувати. Мій досвід показує, що це рідко правда. Більшість із них майже грамотні; деякі можуть написати зв’язаний список, не рухаючи губами (не жартую: згадаймо мій попередній коментар про кімнату, повну студентів CS, жоден з яких не знав, як побудувати зв’язаний список). Деякий код, який я бачив у продакшені, не пройшов би рев’ю. Уявіть, що будівлі можна було б будувати без будь-якої інспекції, яка засвідчує їхню безпечність. Я сам мусив ходити до муніципалітету, щоб отримати дозвіл на будівництво для домашніх проєктів. Мені потрібно було надати креслення. Я достатньо досвідчений, щоб знати, що не маю уявлення, як побудувати терасу чи укріпити будівлю — але я знаю, як найняти людей, які це вміють. Якби я збирався будувати кар’єру архітектора, я б точно шукав найкращих людей, у яких можна навчитися.

Правдива історія: одного разу я прийшов, щоб отримати дозвіл на будівництво. Людину переді мною працівник за стійкою допитував про такі речі, як міцність з’єднання тераси з будинком, навантаження на підлогу тощо. Я подумки думав: «Мені кінець. Я не зможу відповісти на все це!» Настала моя черга. Я подав креслення. Людина за стійкою підняла документи, глянула на тиснений відбиток у нижньому куті — «Зареєстрований професійний архітектор» — глянула на мене й сказала: «15 доларів». І все. Креслення обійшлися мені в 400 доларів. І це було варте кожного цента.

Одна з причин, чому я вважаю себе хорошим програмістом — це те, що я вчився в найкращих. І, якщо вже на те пішло, також і в найгірших (у стилі: «Я ніколи не побудую щось настільки халтурне»). Але безумовно найцінніше я засвоїв від програмістів, які були досвідченішими й мали кращий смак, ніж я (особливо у свої 20). До тридцяти я вже був хорошим, і з того часу постійно намагаюсь ставати кращим. Я читаю багато коду. Я бачу багато хороших ідей. І намагаюся зробити їх частиною свого стилю.