Обучение
Как мы учимся программировать? Позвольте рассказать вам одну историю о наставниках и учениках.
Digi-comp I, мой первый компьютер
В 1964 году моя мама подарила мне на 12-летие маленький механический компьютер. Он назывался Digi-Comp I и состоял из трех пластиковых триггеров и шести пластиковых конъюнкторов. Выходы триггеров можно было соединять с входами конъюнкторов или наоборот – выходы конъюнкторов со входами триггеров. Короче говоря, устройство позволяло создать трехразрядный конечный автомат.
В комплект входила инструкция с несколькими программами. Чтобы запрограммировать машину, следовало протолкнуть пластиковую трубочку (короткий отрезок соломинки для коктейля) в штифт на триггере. В руководстве было точно указано, куда вставлять трубочки, но ни слова не говорилось о том, что эти трубочки делают. Знали бы вы, как это меня раздражало!
Я часами разглядывал машину и пытался понять, как она работает на самом нижнем уровне; но даже для спасения жизни я бы не смог заставить ее сделать то, что мне нужно. На последней странице руководства было сказано, что если я заплачу доллар, то мне пришлют руководство по программированию машины.
Я послал доллар и стал ждать с нетерпением двенадцатилетнего подростка. Когда книга пришла, я проглотил ее за день. Это было простое изложение булевой алгебры с азами булевой логики, законов ассоциативности и дистрибутивности и теоремы де Моргана. В руководстве было показано, как выразить задачу в виде последовательности логических формул и как сократить эти формулы для 6 конъюнкторов.
Я написал свою первую программу. Я написал уравнения, сократил их и отобразил на трубки и штифты машины. И программа заработала!
Даже сейчас от воспоминаний у меня мурашки бегут по спине. Те впечатления определили судьбу 12-летнего подростка почти полвека назад. Программирование захватило меня, и моя жизнь уже никогда не будет прежней.
Помните момент, когда заработала ваша первая программа? Она изменила вашу жизнь или открыла перед вами путь, с которого вы уже не смогли свернуть?
Я не мог во всем разобраться сам. У меня были наставники. Очень добрые и способные люди (которым я многим обязан) не пожалели времени на то, чтобы написать изложение булевой алгебры, доступное для 12-летнего подростка. Они связали математическую теорию с практическими навыками программирования маленького механического компьютера; благодаря им я смог заставить компьютер сделать то, что мне было нужно.
Я только что снял с полки свой экземпляр этого судьбоносного учебника. Я храню его в пластиковом пакете с застежкой. Время берет свое: страницы пожелтели и стали хрупкими. Но сила слов сияет, как и прежде. Элегантное изложение булевой алгебры занимает всего три страницы неплотного текста. Пошаговый анализ формул каждой из исходных программ до сих пор производит впечатление. Это был настоящий шедевр; работа, которая изменила жизнь по крайней мере одного молодого человека. А я, скорее всего, даже не узнаю имен авторов.
ECP-18 в средней школе
В 15-летнем возрасте, когда я учился в старших классах, мне нравилось проводить время в математической лаборатории. Однажды туда привезли устройство размером с циркулярный станок. Это был учебный компьютер для средних школ, он назывался ECP-18. Нашей школе был предоставлен двухнедельный пробный период.
Я стоял в стороне и слушал разговоры учителей и техников. У машины были 15-разрядные слова (что такое «слово»?) и барабанный накопитель на 1024 слова. (Тогда я уже знал, что это такое, но только теоретически.)
Когда машину включили, она издала свист наподобие того, который издает реактивный самолет при взлете. Я предположил, что это раскручивался барабан. Когда устройство набрало обороты, оно работало относительно тихо.
Машина была очаровательной. Она напоминала офисный стол, над которым возвышалась потрясающая панель управления – как на капитанском мостике боевого корабля. Панель была украшена рядами лампочек, которые также можно было нажимать, как кнопки. Сидя за таким столом, человек ощущал себя словно в кресле капитана Керка.
Я наблюдал за тем, как техники нажимали кнопки. Когда кнопку нажимали, лампочка загоралась, а при повторном нажатии она гасла. Также они нажимали другие кнопки с названиями типа «Загрузить» и «Выполнить».
Кнопки в каждом ряду были объединены в пять групп по три. Мой Digi-Comp тоже был трехразрядным, так что я мог читать восьмеричные цифры в двоичной форме. Было нетрудно понять, что каждая строка представляет пять восьмеричных цифр.
Я слышал, как техники, нажимавшие кнопки, что-то бормочут. Они нажимали 1, 5, 2, 0, 4 в строке «Буфер памяти», говоря при этом: «Сохранить в 204». Они нажимали 1, 0, 2, 1, 3 и бормотали: «Загрузить 213 в аккумулятор». Там был ряд кнопок с подписью «Аккумулятор!»
Через десять минут моему 15-летнему разуму было абсолютно ясно, что 15 означает «сохранить», а 10 – «загрузить», что в аккумуляторе находились сохраняемые или загружаемые данные, а остальные числа были номерами одного из 1024 слов на барабане. (Так вот что такое «слово»!)
Слово за слово (непреднамеренный каламбур), мой пытливый ум все глубже проникал в коды инструкций и концепции. К тому моменту, когда техники ушли, я уже понимал основные принципы работы машины.
Этим же днем, во время часов для самостоятельной работы, я пробрался в математическую лабораторию и начал экспериментировать с компьютером. К тому времени я уже отлично знал, что проще попросить прощения, чем добиться разрешения! Я ввел программу, которая умножала содержимое аккумулятора на 2 и прибавляла 1. Я ввел в аккумулятор 5, запустил программу – и увидел в аккумуляторе 13! Программа работала!
Я ввел еще несколько таких же простых программ, и они тоже работали так, как положено. Я был повелителем Вселенной!
Сутки спустя я понял, насколько я был глуп – и как мне повезло. Я нашел в лаборатории памятку, в которой были перечислены все инструкции и коды операций, в том числе и тех, которые я не мог узнать, наблюдая за техниками. Я с радостью узнал, что известные мне коды были интерпретированы правильно, а остальные вызвали прилив энтузиазма. Однако среди новых инструкций я заметил инструкцию остановки HLT. Так уж совпало, что инструкция остановки была словом из одних нулей. И еще совпало то, что я включал в конец каждой из своих программ слово из одних нулей, чтобы стереть содержимое аккумулятора. Концепция остановки мне просто не приходила в голову. Мне казалось, что программа сама остановится, когда все сделает!
Помню, я однажды сидел в математической лаборатории, наблюдая за тем, как один из учителей боролся со своей программой. Он пытался ввести два числа в десятичной форме с подключенного телетайпа, а потом распечатать их сумму. Каждый, кто пытался программировать подобные задачи на машинном языке мини-компьютеров, знает, что они отнюдь не тривиальны. Нужно прочитать символы, разбить их на цифры, затем преобразовать в двоичную форму, просуммировать, преобразовать их обратно в десятичную систему и закодировать в символы. Поверьте, когда программа вводится в двоичном виде с передней панели, все намного хуже!
Я наблюдал за тем, как он вставил в программу команду остановки и запустил. (О! Хорошая мысль!) Примитивная точка прерывания позволила ему проанализировать содержимое регистров и понять, что сделала программа. Помню, как он пробормотал: «Ого! Как быстро!»
Понятия не имею, какой алгоритм он использовал. Такое программирование для меня еще оставалось чем-то вроде волшебства. И он ни слова не сказал мне, пока я смотрел ему через плечо. Никто не говорил со мной об этом компьютере. Думаю, меня считали помехой, на которую не стоит обращать внимания, – чем-то вроде мошки, порхающей по лаборатории. Достаточно сказать, что ни ученик, ни учителя не обладали высокими навыками социальных коммуникаций.
В итоге его программа заработала. Выглядело это потрясающе: он медленно вводил два числа, потому что, несмотря на более ранние восклицания, компьютер работал довольно медленно (подумайте, сколько времени занимало чтение последовательных слов с вращающегося барабана в 1967 году). Когда он нажал «ввод» после второго числа, компьютер яростно помигал лампочками, а потом начал выводить результат. На каждую цифру уходило около секунды. Он вывел все цифры кроме последней, потом секунд пять мигал еще яростнее, вывел последнюю цифру и остановился.
Откуда взялась пауза перед последней цифрой? Этого я так и не узнал. Но зато я понял, что выбор решения задачи может иметь принципиальные последствия для пользователя. Даже при том, что программа выводила правильный ответ, с ней все равно было что-то не так.
Это тоже было обучение. Конечно, не такое обучение, на какое я бы мог надеяться. Было бы намного лучше, если бы один из этих учителей взял меня под опеку и стал работать со мной. Но даже наблюдение за ними позволяло мне стремительно получать новые знания.
Нетрадиционное обучение
Я рассказал эти две истории, потому что они описывают два совершенно разных типа обучения, ни один из которых обычно не подразумевается под этим термином. В первом случае я учился у авторов очень хорошо написанного учебника. Во втором случае я учился, наблюдая за людьми, которые активно старались не обращать на меня внимания. В обоих случаях приобретенные знания были глубокими и основательными.
Конечно, у меня были и другие учителя. Добрый сосед, работавший в Teletype, подарил мне коробку с 30 телефонными реле. Вот что я вам скажу: дайте парню реле и трансформатор от игрушечной железной дороги – и он покорит мир!
Другой добрый сосед увлекался любительским радио и научил меня пользоваться мультиметром (который я незамедлительно сломал). Владелец магазина офисных принадлежностей разрешал мне зайти и «поиграть» с его очень дорогим программируемым калькулятором. А еще рядом был отдел продаж Digital Equipment Corporation, который разрешал мне зайти и «поиграть» с PDP-8 и PDP-10.
Также был большой Джим Карлин – BAL-программист, который спас меня от увольнения с первой работы. Он помог отладить программу на Cobol, выходившую за пределы моего понимания. Он научил меня читать дампы ядра, форматировать код при помощи пустых строк, звездочек и комментариев. Он дал мне первый толчок на пути к мастерству. Жаль, что я не мог отплатить услугой за услугу, когда гнев моего начальства обрушился на него год спустя.
Но по правде говоря, список подошел к концу. В начале 1970-х годов было не так уж много опытных программистов. Во всех остальных местах, где я работал, я был самым опытным. Не было никого, кто бы помог разобраться мне, что такое настоящее профессиональное программирование. Не было образца для подражания, который бы научил меня, как себя вести и на что обращать внимание в первую очередь. Все это мне пришлось узнавать самому, и процесс был отнюдь не из простых.
Горький опыт
Как я уже рассказывал, меня все-таки уволили с той работы по автоматизации производства в 1976 году. Хотя с технической точки зрения я был очень компетентным, я не научился обращать внимание на бизнес и его цели. Даты и сроки ничего не значили для меня. Я забыл о важной демонстрации программы в понедельник утром, оставил систему в неработоспособном состоянии в пятницу и опоздал на работу в понедельник под осуждающими взглядами всех остальных. Мой начальник прислал мне уведомление о том, что я должен немедленно изменить свое отношение к работе или меня уволят. Для меня это был «тревожный звонок»: я пересмотрел свои взгляды на жизнь и карьеру и внес существенные изменения в свое поведение – кое-что об этом вы уже читали. Но было поздно, слишком поздно. Маховик был уже запущен, и мелочи, на которые ранее никто не обратил бы внимания, вдруг стали важны. Итак, как я ни старался, в конечном итоге меня выпроводили из фирмы.
Не стоит и говорить, что приносить такие вести беременной жене с двухлетней дочерью невесело. Но я собрался с духом и перенес полезные жизненные уроки на следующую работу, на которой я оставался 15 лет и которая заложила настоящий фундамент текущей карьеры.
В конечном итоге я выжил и преуспел. Но должен быть и другой, более эффективный путь. Мне было бы намного проще, если бы у меня был настоящий наставник – тот, кто покажет мне «что к чему»; человек, за которым я мог бы наблюдать, помогая с выполнением мелких задач, который будет рецензировать и направлять мою раннюю работу. Человек, который станет образцом для подражания и научит меня необходимым профессиональным ценностям и навыкам. Сэнсэй. Руководитель. Наставник.
Ученичество
А что происходит в медицине? Думаете, больницы берут на работу выпускников и с первого дня отправляют их в операционную выполнять операции на сердце? Конечно, нет.
Профессиональная медицина разработала методологию интенсивного обучения, плотно укутанную ритуалами и сглаженную традицией. Профессиональная медицина наблюдает за университетами и следит за тем, чтобы выпускники получали лучшее образование. В процессе учебы время приблизительно поровну распределяется между занятиями в классах и клинической работой в больницах с профессионалами.
После выпуска и до получения лицензии новоиспеченные врачи обязаны пройти годичную практику под руководством специалистов, которая называется интернатурой. Происходит интенсивное обучение на месте работы: интерна окружают образцы для подражания и наставники.
После завершения интернатуры разные медицинские специализации требуют от трех до пяти лет дальнейшей практики, называемой ординатурой. Врач-стажер постепенно набирается уверенности, выполняя еще более серьезные задачи, оставаясь в окружении (и под наблюдением) более опытных врачей.
Многие специальности требуют от одного до трех лет аспирантуры, в течение которой продолжается обучение студента по специальности и накопление практического опыта.
И только после этого молодой специалист допускается к экзаменам и аттестации.
Мое описание профессиональной медицины несколько идеализировано и, вероятно, крайне неточно. Но факт остается фактом: когда риск велик, никто не отправляет недавних выпускников в операционную, время от времени подбрасывая им пациентов и ожидая, что из этого выйдет что-нибудь путное. Так почему же это происходит в области программирования?
Конечно, количество смертей из-за ошибок в программах относительно невелико. С другой стороны, экономические потери весьма значительны. Из-за недостаточной подготовки своих разработчиков компании теряют огромные суммы.
По какой-то причине в отрасли разработки ПО родилась мысль, что программист есть программист и сразу же после получения диплома можно приступать к написанию кода. Некоторые фирмы нанимают парней прямо со школьной скамьи, собирают из них «группы» и поручают строить критически важные системы. Безумие!
Художники так не поступают. Сантехники так не поступают. Электрики так не поступают. Наверное, даже повара в «МакДональдсе» так не поступают! Мне кажется, что компании, нанимающие выпускников в области компьютерных технологий, должны тратить на их обучение больше, чем «Макдональдс» тратит на подготовку своих работников.
И не стоит обманывать себя, будто это не важно. Ставки высоки. Наша цивилизация живет на программах. Именно программы занимаются перемещением и обработкой информации, наполнившей нашу повседневную жизнь. Программы управляют двигателями, передачей и тормозами наших машин. Они поддерживают баланс наших банковских вкладов, рассылают счета и получают оплату. Программы стирают нашу одежду и сообщают время. Они выводят изображение на экраны телевизоров, отправляют текстовые сообщения, делают телефонные звонки и развлекают нас, когда нам скучно. Они повсюду.
Раз мы доверяем разработчикам все аспекты наших жизней, от пустяковых до самых важных, на мой взгляд, разумный период обучения и практики под руководством специалистов будет вполне уместным.
Период ученичества
Итак, как же молодые выпускники должны вливаться в ряды профессиональных программистов? Какой путь они должны пройти? С какими препятствиями столкнуться? Каких целей они должны достичь? Давайте рассмотрим профессиональные уровни программистов по убыванию квалификации.
Мастер
К этой категории относятся программисты, возглавлявшие более одного серьезного программного проекта. Как правило, они имеют более чем 10-летний стаж работы с разными системами, языками и операционными системами. Они умеют руководить и координировать работу нескольких команд, являются квалифицированными проектировщиками и разработчиками архитектур и могут запросто запрограммировать что угодно. Им предлагались руководящие должности, но они либо отклонили предложение, либо вернулись обратно после согласия, либо интегрировали их в свою основную техническую роль. Для поддержания своей квалификации в этой роли они читают техническую литературу, учатся, тренируются, работают и учат. Именно мастера несут ответственность за реализацию проекта с технической стороны.
Ремесленник
Рядовые программисты – обученные, компетентные и энергичные. В этот период своей карьеры они учатся работать в группах и выполнять функции руководителя. Они хорошо разбираются в современной технологии, но обычно им не хватает опыта работы с разнообразными системами. Обычно ремесленник знает один язык, одну систему, одну платформу; но он старается узнать больше. Стаж работы в этой категории сильно различается; среднее значение составляет около 5 лет. На ближнем конце оси находятся недавние ученики, а на дальнем – зарождающиеся мастера.
Наставниками ремесленников являются мастера или более опытные ремесленники. Молодым ремесленникам редко предоставляется самостоятельность. За их работой плотно наблюдают, а их код проверяется. По мере накопления опыта самостоятельность растет, контроль становится менее прямолинейным и в конечном итоге преобразуется в равноправное рецензирование кода.
Ученики/интерны
Карьера выпускника начинается с позиции ученика. У учеников нет никакой самостоятельности – их очень плотно контролируют ремесленники. Сначала ученики вообще не выполняют никаких задач, просто помогая ремесленникам. Это должно быть время чрезвычайно интенсивного парного программирования. Именно в это время изучаются и закрепляются методы и приемы. Именно в это время закладывается фундамент системы профессиональных ценностей.
Ремесленники становятся учителями. Они следят за тем, чтобы ученики знали принципы и паттерны проектирования, методы и ритуалы. Ремесленники обучают их TDD, рефакторингу, искусству оценки и т. д. Они назначают ученикам книги, раздают упражнения и учебные задачи; они следят за их прогрессом.
Ученичество должно длиться не менее года. За это время, если ремесленники пожелают принять новичка в свои ряды, они обращаются к мастерам с рекомендацией. Мастера изучают новичка – как в личном собеседовании, так и посредством анализа достижений. Если мастера соглашаются, то ученик переходит в ремесленники.
Реальность
И снова скажу, что это описание идеализированное и гипотетическое. Но если немного изменить терминологию, вы поймете, что оно не так уж сильно отличается от сегодняшней ситуации. Выпускников опекают молодые руководители групп, которых опекают руководители проектов и т. д. Проблема в том, что в большинстве случаев опека имеет нетехническую природу! В большинстве компаний технического контроля нет вообще. Программисты получают прибавки и повышения, потому что… потому что так положено.
Различия между сегодняшним положением дел и моей идеализированной программой заключается в ориентированности последней на техническое обучение, опеку и контроль. Оно проявляется в самом представлении о том, что профессиональные ценности и техническую сметку нужно объяснять, культивировать и взращивать. В нашем современном стерильном подходе отсутствует ответственность старших за обучение молодежи.