Главная страница Visual 2000 · Общий список статей
Поговорим о программировании.Андрей Колесов
© Андрей Колесов, 2002
"Иногда во время этой работы здравый смысл подсказывал мне,
чтобы я перестал навязывать учащимся свои идеи,
но, к сожалению, гордость и обыкновенное самолюбие взяли верх".
Эд Йордан [3]
"Мастерство достигается не запоминанием всех мельчайших подробностей темы,
а доскональным понимаем тех базовых принципов, на которых она
основана".
Дан Эпплман [4]
Летом 2000 года при подготовке сразу нескольких материалов для "КомпьютерПресс" N 9/2000 (тема номера "Средства разработки") я рискнул написать статью, содержание и стиль которой достаточно точно отражает ее название — "Размышления бывшего программиста". Желание поболтать по душам на тему "программирования вообще" появилось давно, но меня всегда останавливало осознание того, что я уже несколько лет как отошел от реального программирования (создания продуктов, а не баловства на уровне написания тестовых примеров).
В то же время из общения с разработчиками, в том числе с теми, кто порой обращается ко мне как к автору статей на темы программирования, у меня сформировалось четкое убеждение, что, несмотря на огромный прогресс в области средств разработки, базовые принципы создания ПО (а тем более программирования) остались теми же, что и три десятилетия назад. В частности, читая многие публикации на тему организации разработки, проектирования и кодирования, довольно часто ловишь себя на мысли, что новое — это хорошо забытое старое.
Второе сомнение: будут ли размышления "бывшего" интересны современным программистам? На этот вопрос я не знаю точного ответа, но в данном случае важнее, что на мое предложение продолжить "размышления" редакция "КомпьютерПресс" ответила согласием. К сожалению, регулярного сериала не получилось по моей вине: хотя какие-то идеи постоянно возникали, времени на их реализацию явно не хватало, и уже больше года я утешал себя мыслью, что "в следующем месяце — железно". Однако иллюзии на сей счет у меня окончательно развеялись, и это послужило стимулом сделать усилие, чтобы поставить этой статьей точку в "Размышлениях бывшего программиста".
Что же такое хорошая программа?
"Бывает очень трудно объяснить человеку, как писать хорошую программу,
если он упорно отрицает мой взгляд на то, что называть хорошей
программой".
Эд Йордан [3]
Этот вопрос обсуждался в 3-й части моих заметок, и дискутировать на эту тему можно довольно много. Некоторые дополнительные соображения по этому поводу изложены, в частности, в статьях "Go to — выражение из четырех букв" и "Это сладкое слово "XML".
Вернуться к вопросу определения "хорошей программы" заставила меня жаркая дискуссия с разработчиками, которые узнали свое произведение в последней из этих двух публикаций. Основной их тезис был такой: "Неважно, как написана программа, главное, чтобы она работала". А в оправдание неэффективности и "неэлегантности" их кода было сказано: "Ведь мы же не знали, что кому-то вздумается опубликовать исходный код в Интернете для всеобщего обозрения". Последний аргумент выглядит довольно странно — ведь руки моют перед едой не для того, чтобы понравиться знакомой барышне, а из соображений гигиены, то есть для сохранения собственного здоровья. Другое дело, что если барышня увидит грязные руки, то у нее может отпасть всякое желание продолжать знакомство... Тут аналогия с разработчиком и заказчиком видится совершенно полной.
Так что по этому поводу хотелось бы еще раз высказать свою точку зрения: работоспособность программы является необходимым, но не достаточным условием. Нельзя проводить оценку программы в отрыве от сроков ее написания, трудозатрат, возможности сопровождения и ряда других характеристик. И вот именно здесь на первый план выходит тема "стиля программирования", потому что даже при поверхностном рассмотрении легко увидеть, что речь тут идет не о моде или абстрактных правилах хорошего тона, а о насущных вопросах повышения производительности работы программиста, увеличения надежности программ, снижения стоимости их сопровождения, обеспечения групповой работы и т.д. Более того, в ряде случаев качество исходного кода является даже более приоритетным, чем его работоспособность. Я имею в виду в первую очередь фрагменты учебного кода.
Комментарии в исходном тексте — это просто классический пример вечного вопроса программирования. Казалось бы, все "точки над i" расставлены еще 30 лет назад, так нет же — огромное множество современных программистов продолжают считать комментарии блажью начальников проектов, признаком непрофессионализма и пр.
Вот что писал по этому поводу Эд Йордан [3] более 25 лет назад: "В области программирования ничто не заслуживает большего порицания, чем программа без комментариев. Программисту можно простить многие прегрешения и фантазии, однако ни одному программисту, как бы ни был он умен и опытен, нельзя простить программу, не оформленную и не содержащую комментариев... Только глупец может идти незнакомым лесом, не оставляя за собой знаков. Писать программы без комментариев — это то же самое, что пробираться джунглями Амазонки с завязанными глазами..." <*>
* Примечание. У Эда Йордана есть совершенно замечательный раздел по этому вопросу (с. 22-25), в котором приведен отличный пример с суперпрограммистом.
Хотел бы сразу сказать: конечно же, развитие языков программирования во многом решило проблему самодокументирования, когда сам код наглядно говорит, что делает программа. Понятно, что для ассемблерного кода:
cmp dl,0 jne Attrnext
или при использовании идентификаторов ограниченного размера:
If A > 0 Then B = C + D
проблема описания программы выглядела совсем иначе, чем для современных языков:
If blnFlagShow = True Then Me.WindowState = vbMaximized End If
Прежде чем рассказывать о том, как и зачем писать комментарии, приведу несколько характерных доводов (на самом деле — оправданий) по поводу их отсутствия в программах:
Наверняка, каждый из современных руководителей проектов не раз слышал такое от своих сотрудников. Но все приведенные выше высказывания я взял из той же книги Йордана выпуска 70-х годов. Лишь несколько из имеющихся у него "доводов" действительно устарели (например, желание экономить дисковую память и лимит времени перфоратора при вводе исходного текста).
А из более современной практики хотел бы добавить такие тезисы:
Против первого высказывания трудно придумать весомые аргументы, кроме пожелания заняться сопровождением программ без описаний. Что же касается двух последних, то здесь хотелось бы сразу привести контрдоводы.
Комментарий чаще все нужен не для того, чтобы понять, "что делает программа" (это можно понять из самого кода), а "почему" программист использует именно этот код. Совершенно очевидно, что следующие комментарии не нужны (а может быть даже вредны), так как просто дублируют код:
A = A + 1 ' увеличиваем A на 1 Exit Sub ' завершение процедуры
А вот примеры "поясняющих" комментариев, которые вряд ли сможет расставить какая-то утилита:
ShowCol.AllowDBNull = False ' неопределенное значение недопустимо InsertFlag = Not InsertFlag ' изменение режима ввода символов If index = 0 Or KeyAscii = 127 Then ' переход в режим редактирования
А вот еще один реальный пример. Около десяти лет назад я отправил в редакцию одного журнала статью, которая содержала такой фрагмент кода:
out dx,al mov al,es:[bx] ; нужен ли этот оператор? mov es:[bx],cl mov dx,3CEh mov al,5
Редактор в журнале оказался очень внимательным: он изучил код и увидел в нем явно лишний оператор (который помечен комментарием). Действительно, в нем выполняется пересылка какого-то значения в регистр A, который нигде не используется, а двумя операторами ниже формируется еще раз. Поэтому редактор удалил эту строку, а после публикации мне стали звонить читатели и говорить, что моя программа не работает.
Дело в том, что данный ассемблерный код из-за специфического использования источника информации (es:[bx] — адрес видеопамяти) выполняет не только формирование регистра A, но и скрытого регистра задвижки (другого способа в процессоре 286 не было). Так вот, если бы я зафиксировал, зачем делается этот трюк, в комментарии, то никакого недопонимания между мной и редактором не возникло бы. Конечно, править авторский код редактору в любом случае недопустимо, но такая ситуация могла бы легко возникнуть не только при сопровождении программы другим разработчиком, но и если бы мне самому пришлось корректировать код пару месяцев спустя (я бы просто уже забыл о набитых шишках).
Кроме того, порой бывает очень важно запротоколировать в исходном коде сам процесс разработки и отладки. Например, вы можете обнаружить, что какая-то вроде бы очевидная конструкция работает неэффективно (или даже сбоит), поэтому нужно использовать более хитроумный прием. Конечно, такой опыт лучше зафиксировать.
Из сказанного можно сделать важный вывод: комментарии должен писать сам автор программы, причем не после завершения ее отладки, а в процессе разработки. Но программистов, которые не пишут комментарии (я не использую слово "любят", так как понятия "любимый" и "нужный" не всегда совпадают), еще можно понять. Но как вам понравятся следующие высказывания со стороны преподавателей:
Конечно же, комментарии не являются самоцелью и в любом случае не заменят плохих кодов. Понятно также, что большие трудности могут возникнуть и в случае, когда программа насыщена комментариями, но при этом они (ссылаюсь здесь на [3]):
Как писать комментарии? Прежде всего, нужно придерживаться некоторой системы. При работе группы руководитель проекта может легко зафиксировать минимальные требования к оформлению кода в регламенте из нескольких пунктов. (К вопросу комментариев непосредственно примыкает проблема выбора идентификаторов переменных и процедур. Тут тоже крайне желательно выработать некоторые общие подходы.) Со своей стороны я могу предложить такой минимальный джентльменский набор:
О тестировании и написании документации
В старые добрые времена разработчики чаще всего сами писали код, сами его тестировали, сами писали документацию. Современная технология ориентируется на глубокую систему разделения труда: появились большие новые категории участников процесса разработки программных продуктов — тестеры, технические писатели.
Никто не собирается оспаривать необходимость такой специализации, но все же нужно иметь в виду, что проектирование-кодирование-тестирование-отладка-документирование-сопр- овождение — это единый, взаимосвязанный процесс создания ПО. А как известно, оптимизация отдельного элемента (без учета взаимосвязей) далеко не всегда приводит к повышению эффективности системы в целом. То есть писать программы нужно изначально с учетом всех последующих этапов ее жизненного цикла.
Что касается тестирования, то тут следует вспомнить, что одной из главных причин перехода к структурному программированию в начале 70-х годов была необходимость снижения затрат на тестирование. Именно этот аспект был в центре внимания фундаментальной работы Э.Дейкстры [2]. (В 1972 году он сформулировал очевидный сегодня постулат: "Тестирование программ может служить для доказательства наличия ошибок, но никогда не докажет их отсутствия!")
Действительно, идеальный вариант тестирования — это проверка всех возможных состояний программы. Понятно, что это нереально для сколько-нибудь сложной программы, поэтому проблема сводится к решению вероятностной оптимизационной задачи — минимизировать усилия на отладку (число проверяемых состояний программы) для достижения приемлемого уровня ее работоспособности. Решение заключается в разбиении большой программы на максимально независимые компоненты, которые тестируются автономно, а потом отдельно проверяются взаимосвязи между ними.
Я не буду детально углубляться в этот вопрос и говорю об этом лишь с целью подчеркнуть: одна из ключевых задач программирования (еще один признак "хорошей" программы!) — минимизация затрат на тестирование. Но есть и другая сторона этой медали — оптимизация процесса тестирования требует знания внутренней структуры программы (чтобы не заниматься хаотичным "тыканьем пальцем в небо", а целенаправленно исследовать наиболее критичные точки). Не говоря уже о том, что устанавливать причину найденных ошибок придется самому разработчику, о чем также нужно думать заранее. <** >
** Примечание. В широком понятии "отладка" — это процесс обнаружения наличия ошибок (то есть тестирование), поиск и устранение причин ошибок. В узком смысле под отладкой часто подразумевают только вторую часть этой работы.
В целом сказанное о тестировании относится и к написанию документации. Но тут есть один дополнительный нюанс. Из собственного опыта подготовки руководств для своих же программ я могу сказать: сложность описания программы напрямую коррелирует с удобством работы с ней (как известно, такие описания делаются и для пользователей, и для сопровождающих программистов). Довольно часто именно в ходе написания таких руководств я понимал, что был выбран далеко не оптимальный интерфейс или внутренняя структура, и переписывал код.
Хочу подчеркнуть — я это делал не только из желания обеспечить комфортные условия для клиентов. Тут были и гораздо приземленные причины — мне было проще скорректировать код, снизив свои затраты на подготовку документации.
К сожалению, документирование программ часто рассматривают как некий автономный этап после полного завершения их отладки. Но на самом деле здесь нужно поддерживать обратную связь, так как написание документации является одновременно оценкой качества ПО. Вполне вероятно, что тут могут быть обнаружены проблемы, которые потребуют вернуться к этапу проектирования... Как бы то ни было, любому программисту пойдет только на пользу получение хотя бы небольшого опыта работы в качестве тестера и технического писателя.
Говоря об общности базовых принципов программирования на протяжении всей истории его существования, нужно, конечно, иметь в виду и то, что технология эта развивается и знака тождественного равенства между разработкой ПО 70-х и 90-х годов поставить никак нельзя. Хотя все очень похоже... Но есть один принципиально новый элемент современного программирования, которого не было два десятилетия назад и которое оказывает очень серьезное влияние на разработку ПО. Его имя — маркетинг.
Действительно, почитайте публикации 70-х годов. Там ведется обсуждение проблем программирования на академическом уровне, ученые проводят сравнительный анализ языков, рассматривают пути повышения эффективности работы программистов и самих программ, ищут истину... Бескорыстно! Если обсуждается конкретный язык программирования, то практически не уточняется, кто является разработчиком компилятора и о какой версии идет речь. Не говоря уже о том, что одной из популярных тем тех лет был сравнительный анализ разных языков. (Кто-нибудь из читателей видел современную книгу со сравнительным анализом, например, VB и Delphi? В лучшем случае в одной книге есть отдельные разделы по разным средствам, но без каких-то попыток сопоставления.)
Сегодня все выглядит иначе. Разработчик в первую очередь выбирает производителя инструментария (точнее, платформу), а уж потом решает, какое конкретно средство использовать. Компьютерный мир четко разделился на поставщиков и пользователей, которые в соответствии с законом диалектики живут в условиях единства и борьбы противоположностей.
На эту тему можно говорить очень много, но сейчас мне хотелось бы подчеркнуть только одно — разработчики (как и все другие ИТ-пользователи) находятся в условиях жесткого маркетингового давления со стороны производителей ИТ-платформ. В последнее время мне довольно часто приходится бывать на разного рода "технических" мероприятиях, и я смею утверждать, что значительная часть времени на них отводится чему-то похожему на сеансы массового гипноза, зомбирования или "промывания мозгов".
Я совершенно спокойно слушаю высказывания представителей компаний-поставщиков, что цель их работы — повышение благосостояния пользователей. Но это совсем не означает, что я это воспринимаю всерьез. Ведь базовый принцип рыночной экономики заключается в том, что целью работы каждого коммерческого предприятия является получение прибыли. Для себя, а не для покупателей. Другое дело, что успешный бизнес нельзя вести без учета пожеланий пользователей. Но при этом любая крупная компания будет всячески (в силу своих возможностей) давить на рынок, активно формировать нужный ей спрос.
Все это очень хорошо можно наблюдать на ИТ-рынке. Мы сейчас не будем обсуждать, хорошо это или плохо, что делать, кто виноват и пр. Я хочу только высказать такой совет всем разработчикам: старайтесь отделять реальные технологии от маркетинга.
"Не верь, не бойся, не проси!"
В первой части "Размышлений" я привел названия трех книг, опубликованных еще в 70-х годах, которые оказали огромное влияние на мое формирование как разработчика и до сих пор являются для меня настольными [1-3]. Сильное впечатление от прочтения этих книг во многом объяснялось тем, что в них я и мои коллеги нашли тогда систематическое изложение идей и подходов, к которым мы и сами пришли путем проб и ошибок. Разумеется, мы почерпнули из них и много нового.
Так вот, недавно я обнаружил еще одну книгу, которая произвела на меня примерно такое же впечатление [4]. Ее автор — Дан Эпплман, очень известный американский разработчик. Несколько лет назад он создал компанию Desaware, которая занимает заметные позиции на рынке дополнительных продуктов, в основном для VB. Но еще большую популярность он заслужил как автор целого ряда книг (его серия о Win API для VB в течение почти 10 лет неизменно является бестселлером), а также огромного количества статей, в которых он интересно рассматривает не только технические, но и маркетинговые вопросы. (Если хотите, то можете посмотреть мои более подробные рецензии на книги Дана Эпплмана.)
Его книга, переведенная и опубликованная издательством "Питер", произвела на меня огромное впечатление, потому что она написана именно так (и в таком стиле), как я всегда хотел изложить свое видение проблем современного программирования вообще и с помощью VB в частности. (Конечно, известность Дана Эпплмана для меня является недостижимой, но кое-что общее у нас имеется: я тоже зарабатывал деньги созданием инструментального ПО для Basic/DOS (см. раздел "Повоем на луну Basic-DOS" — и написал немало статей. И еще: последние 15 лет использую средства разработки Microsoft и пишу о них.)
Я искренне советую всем программистам найти и прочитать эту книгу, потому что в ней говорится не столько о VB и основах платформы .NET (это лучшее, на мой взгляд, описание .NET из всего множества публикаций на эту тему), сколько о методике изучения новых инструментальных средств. Красной нитью через изложение проходит также обсуждение вопроса "технология и маркетинг". И сейчас я хочу привести лишь несколько цитат из книги (по поводу них я могу лишь высказать сожаление, что Дан опередил меня с точным изложением моих собственных позиций):
Закончить свои "Размышления" я хочу еще одной цитатой из книги Дана Эпплмана: "Все сказанное мною (или любым другим автором) следует воспринимать скептически и оценивать в контексте конкретной ситуации".
Литература
Брукс Ф. Как проектируются и создаются программные комплексы. Мифический
человеко-месяц — М.: Наука, 1979.
Дейкстра Э. Заметки по структурному программированию (в составе сборника
"Структурное программирование") — М.: Мир, 197
Йордан Э. Структурное проектирование и конструирование программ
— М.: Мир, 1979.
Дан Эпплман. Переход на VB .NET: стратегии, концепции, код — СПб.:
Питер, 2002