Руководство по стилю программирования и конструированию по
Скачать 7.6 Mb.
|
ГЛАВА 33 Личность 813 глупое высказывание. Если программист не изучил C за год или два, еще три года не сыграют особой роли. Подобный вид «опыта» очень слабо связан с произво- дительностью труда. Быстрые изменения информации в сфере программирования создают странную динамику в области «опыта». Во многих отраслях специалист, имеющий за пле- чами массу успехов и достижений, может расслабиться и наслаждаться заслужен- ным уважением. В то же время знания расслабившегося программиста очень бы- стро устаревают. Чтобы поддерживать компетентность, вы должны идти в ногу со временем. Для молодых и энергичных программистов это преимущество. Более пожилые программисты иногда чувствуют, что они уже заслужили свои эполеты, и возмущаются, когда их год за годом принуждают подтверждать квалификацию. Главное то, что опыт может иметь разное качество. Если вы работаете 10 лет, получаете ли вы 10 лет опыта или 1 год опыта 10 раз? Чтобы приобрести истин- ный опыт, вы должны действовать с умом. Если вы постоянно учитесь, вы приоб- ретаете опыт. Если вы не учитесь, о приобретении опыта не может быть и речи, как бы долго вы ни работали. Страсть к программированию Если вы не проводили хотя бы месяц, работая над одной программой — рабо- тая по 16 часов в день, грезя о ней в остальные 8 часов беспокойного сна, ра- ботая несколько ночей подряд над устранением из программы «одной после- дней ошибки», — вы не писали сложную компьютерную программу. Тогда вам трудно понять, что в программировании есть что-то захватывающее. Эдвард Йордон (Edward Yourdon) Настолько щедрая дань богам программирования — едва ли не самый верный путь к неудаче. Ночные бдения позволят вам на какое-то время почувствовать себя самым великим программистом в мире, но потом вам придется потратить несколько недель на исправление дефектов, внесенных в код в безудержном порыве. Во что бы то ни стало вызовите у себя увлечение программированием, но помните, что увлечение никогда не заменит компетентности. 33.9. Привычки Следовательно, нравственные добродетели существуют в нас не от приро- ды и не вопреки природе… а благодаря приучению мы в них совершенствуем- ся… Ибо если нечто следует делать, пройдя обучение, то учимся мы, делая это… Хорошо строя дома, люди станут добрыми зодчими, а строя худо — худыми… Так что вовсе не мало, а очень много, пожалуй, даже все зависит от того, к чему именно приучаться с самого детства. Аристотель Выработать хорошие привычки крайне важно, потому что очень многое из того, что вы делаете как программист, вы делаете не задумываясь. Например, когда-то вы могли думать о форматировании циклов, но вы не думаете об этом при напи- сании каждого нового цикла. Вы пишете их как привыкли. Это относится почти ко всем аспектам форматирования кода. Когда вы в последний раз всерьез заду- 814 ЧАСТЬ VII Мастерство программирования мывались о своем стиле форматирования? Если вы программируете около пяти лет, скорее всего четыре с половиной года назад. Позднее вы просто следовали привычке. Привычки связаны со многими областями. Так, программисты обычно тщатель- но проверяют индексы циклов и не проверяют операторы присваивания, из-за чего ошибки в операторах присваивания гораздо сложнее искать, чем ошибки индек- сов циклов (Gould, 1975). Вы отвечаете на критику дружелюбно или недружелюбно. Вы всегда стремитесь сделать код удобочитаемым или быстрым или не обращае- те на это никакого внимания. Если при выборе между написанием быстрого или удобочитаемого кода вы каждый раз делаете один и тот же выбор, вы на самом деле не выбираете — вами движет привычка. Взгляните на изречение Аристотеля еще раз и замените слова «нравственные добродетели» на «программистские добродетели». Аристотель утверждает, что вы не предрасположены ни к хорошему, ни к плохому поведению, поэтому вы мо- жете стать как хорошим, так и плохим программистом. Главным способом ста- новления хорошим или плохим в своей области является сама деятельность: стро- ительство в случае строителей и программирование в случае программистов. То, что вы делаете, становится привычкой, и со временем именно привычки начина- ют определять, хороший вы программист или плохой. Билл Гейтс говорит, что любой программист, который впоследствии станет хо- рошим, хорош уже в первые несколько лет. После этого измениться практически невозможно (Lammers, 1986). Если вы программируете уже много лет, вряд ли вы внезапно зададитесь вопросом: «Как я делаю этот цикл быстрее?» или «Как я де- лаю этот код более удобочитаемым?» Это привычки, которые хорошие програм- мисты вырабатывают на самых ранних стадиях обучения. Обучаясь делать что-то, сразу учитесь делать это правильно. В первый раз вы ак- тивно обдумываете свои действия и все еще можете с легкостью изменить свой подход. Выполнив что-то несколько раз, вы начинаете уделять меньше внимания своим действиям, и «сила привычки» берет свое. Проверяйте, что вы приобретае- те именно те привычки, какие хотите. Что, если вы еще не выработали самые эффективные привычки? Как изменить плохую привычку? Будь у меня окончательный ответ на этот вопрос, я бы прода- вал видеокассеты с записями курсов самопомощи!.. Но один стоящий совет я дам. Вы не можете заменить плохую привычку на отсутствие привычки. Именно по- этому люди, пытающиеся бросить курить, сквернословить или переедать, испы- тывают огромные затруднения, пока не заменят старую привычку на какую-то другую, например, жевание жевательной резинки. Легче заменить старую привычку на новую, чем полностью избавиться от привычки. Таким образом, попробуйте выработать новые, эффективные привычки. Например, выработайте привычку писать класс на псевдокоде перед кодированием или тщательно читать код перед его компиляцией. Тогда вам не придется беспокоиться об избавлении от плохих привычек — они естественным путем будут вытеснены новыми привычками. ГЛАВА 33 Личность 815 Дополнительные ресурсы «Человеческому фактору» в разработке ПО посвящены сле- дующие материалы. Dijkstra, Edsger. «The Humble Programmer.» Turing Award Lec- ture. Communications of the ACM 15, no. 10 (October 1972): 859– 66. Эта классическая работа способствовала началу иссле- дования степени зависимости программирования от ум- ственных способностей программиста. Дейкстра постоянно подчеркивает мысль, что основная задача программирования — обуздание огромной сложности ком- пьютерных наук. Он утверждает, что программирование является единственной профессией, представителям которой приходится иметь дело с девятью порядка- ми разницы между самым низким и самым высоким уровнями детальности. Мно- гие мысли Дейкстры свежи и по сей день, однако эту работу интересно прочи- тать хотя бы только из-за ее исторического значения. Вы почувствуете, что зна- чило быть программистом на ранних этапах развития вычислительной техники. Weinberg, Gerald M. The Psychology of Computer Programming: Silver Anniversary Edition. New York, NY: Dorset House, 1998. В этой классической книге подробно рассмат- ривается идея обезличенного программирования и другие аспекты человеческой стороны программирования. Она содержит много увлекательных историй и яв- ляется одной из самых увлекательных книг, посвященных разработке ПО. Pirsig, Robert M. Zen and the Art of Motorcycle Maintenance: An Inquiry into Values. William Morrow, 1974. Пирсиг подробно обсуждает «качество» в контексте обслуживания мотоциклов. Во время написания этой книги Пирсиг работал техническим писа- телем в отрасли программирования, и его проницательные комментарии отно- сятся к психологии программирования в не меньшей степени, чем к обслужива- нию мотоциклов. Curtis, Bill, ed. Tutorial: Human Factors in Software Development. Los Angeles, CA: IEEE Computer Society Press, 1985. Это великолепная подборка статей, посвященных человеческим аспектам создания программ. 45 статей разделены на следующие категории: психологические модели знаний о программировании, обучение про- граммированию, решение проблем и проектирование, следствия репрезентаций проектирования, характеристики языка, диагностика ошибок и методология. Если программирование — одна из самых сложных интеллектуальных задач в истории человечества, программисты просто обязаны хорошо разбираться в человеческих умственных способностях. Кроме того, эти статьи помогут вам узнать, как лично вы можете стать более эффективным программистом. McConnell, Steve. Professional Software Development. Boston, MA: Addison-Wesley, 2004. В седьмой главе этой книги обсуждаются вопросы личности и характера програм- мистов. http://cc2e.com/3327 http://cc2e.com/3334 816 ЧАСТЬ VII Мастерство программирования Ключевые моменты 쐽 Способность к написанию программ напрямую зависит от личного характера. 쐽 Важнейшие качества программиста — скромность, любопытство, профессио- нальная честность, творчество и дисциплина, а также «просвещенная» лень. 쐽 Чтобы стать отличным программистом, можно не обладать особым талантом, но необходимо постоянно стремиться к самосовершенствованию. 쐽 Удивительно, но интеллект, опыт и настойчивость вредят программистам не меньше, чем помогают. 쐽 Многие программисты не ведут активного поиска новых сведений и методик, а полагаются на случайные столкновения с новой информацией на работе. Если вы посвятите небольшую долю своего времени чтению книг и изучению про- граммирования, через несколько месяцев вы будете намного превосходить почти всех своих коллег. 쐽 Хороший характер во многом — продукт правильных привычек. Если хотите стать великолепным программистом, выработайте правильные привычки, а все остальное придет само собой. ГЛАВА 34 Основы мастерства 817 Г Л А В А 3 4 Основы мастерства Содержание 쐽 34.1. Боритесь со сложностью 쐽 34.2. Анализируйте процесс разработки 쐽 34.3. Пишите программы в первую очередь для людей и лишь во вторую — для компьютеров 쐽 34.4. Программируйте с использованием языка, а не на языке 쐽 34.5. Концентрируйте внимание с помощью соглашений 쐽 34.6. Программируйте в терминах проблемной области 쐽 34.7. Опасайтесь падающих камней 쐽 34.8. Итерируйте, итерируйте и итерируйте 쐽 34.9. И да отделена будет религия от разработки ПО Связанные темы 쐽 Вся книга Эта книга посвящена главным образом деталям конструирования ПО: созданию высококачественных классов и циклов, выбору имен переменных, форматирова- нию исходного кода, интеграции системы и т. д. Абстрактные вопросы в ней от- части принесены в жертву более конкретным темам. Поскольку конкретные вопросы уже рассмотрены в предыдущих главах, то, чтобы получить представление об абстрактных концепциях, нам нужно лишь вернуться к темам разных глав и посмотреть, как они взаимосвязаны. В этой главе явно об- суждаются абстрактные аспекты программирования, такие как сложность, абстрак- ция, процесс разработки, удобочитаемость кода, итерация и т. д. Эти аспекты во многом объясняют разницу между хакерством и мастерством разработки ПО. 34.1. Боритесь со сложностью Стремление к снижению сложности играет такую важную роль в программировании, что в главе 5 управление слож- ностью получило статус Главного Технического Императи- http://cc2e.com/3444 Перекрестная ссылка О важно- сти склада ума для борьбы со сложностью см. раздел 33.2. 818 ЧАСТЬ VII Мастерство программирования ва Разработки ПО. Конечно, соблазнительно попытаться сыграть героя и сражаться с компьютерными проблемами на всех уровнях, однако никто не обладает умом, способным охватить девять порядков разницы в подробности. В компьютерных науках разработаны многие интеллектуальные инструменты борьбы с такой слож- ностью, которые мы уже затрагивали в других главах. 쐽 Разделите систему на подсистемы на уровне архитектуры, чтобы концентри- роваться в каждый конкретный момент времени на меньшей части системы. 쐽 Тщательно определяйте интерфейсы классов, чтобы можно было игнорировать внутреннее устройство классов. 쐽 Поддерживайте абстракцию, формируемую интерфейсом класса, чтобы не запоминать ненужных деталей. 쐽 Избегайте глобальных данных, потому что их использование значительно уве- личивает процент кода, который нужно удерживать в уме в любой момент времени. 쐽 Избегайте глубоких иерархий наследования, потому что они предъявляют высокие требования к интеллекту. 쐽 Избегайте глубокой вложенности циклов и условных операторов, поскольку их можно заменить на более простые управляющие структуры, позволяющие бережнее расходовать умственные ресурсы. 쐽 Избегайте операторов goto, так как они вносят в программу нелинейность, за которой большинству людей трудно следовать. 쐽 Тщательное определите подход к обработке ошибок, вместо того чтобы исполь- зовать произвольную комбинацию разных методик. 쐽 Систематично используйте встроенный механизм исключений, поскольку он может стать нелинейной управляющей структурой, которую при недисципли- нированном применении понять почти так же трудно, как и операторы goto. 쐽 Не позволяйте классам превращаться в монстров, достигающих размера целых программ. 쐽 Поддерживайте методы короткими. 쐽 Используйте ясные, очевидные имена переменных, чтобы не вспоминать де- тали вроде « i — это индекс счета, а j — индекс клиента или наоборот?». 쐽 Минимизируйте число параметров, передаваемых в метод, или, что еще важ- нее, передавайте только те параметры, которые нужны для поддержания аб- стракции, формируемой интерфейсом метода. 쐽 Используйте соглашения, чтобы не запоминать произвольные, несуществен- ные различия между разными фрагментами кода. 쐽 В целом боритесь по мере возможности с тем, что в главе 5 было названо «не- существенной сложностью». Создавая для сложного теста булеву функцию и абстрагируя суть теста, вы упро- щаете код. Заменяя сложную цепь логических структур на обращение к таблице, вы делаете то же самое. Создавая хорошо определенный согласованный интер- фейс класса, вы избегаете тревоги насчет деталей реализации класса и в целом упрощаете свою работу. ГЛАВА 34 Основы мастерства 819 Сутью соглашений кодирования также является преимущественно снижение слож- ности. Стандартизуя решения о форматировании, циклах, именах переменных, нотациях моделирования и т. д., вы освобождаете умственные ресурсы, которые пригодятся вам для концентрации на более сложных аспектах программирова- ния. Одна из причин таких жарких споров по поводу соглашений кодирования состоит в том, что выбор того или иного варианта по сути произволен, хотя и имеет некоторую эстетическую основу. Наиболее страстно люди спорят о самых небольших различиях соглашений. Соглашения наиболее полезны, когда освобож- дают вас от принятия и защиты несущественных решений, и менее ценны, если налагают ограничения в более важных областях. Особенно мощным средством управления сложностью является абстракция в раз- ных проявлениях. Программирование развивается преимущественно за счет по- вышения абстрактности программных компонентов. Фред Брукс утверждает, что самым крупным достижением в компьютерных науках можно считать переход от машинного языка к высокоуровневым языкам: он освободил программистов от забот об особенностях отдельных устройств и позволил сосредоточиться на са- мом программировании (Brooks, 1995). Другим важным достижением стало изоб- ретение методов, за которыми последовали классы и пакеты. Функциональное именование переменных, отвечающее на вопрос «что?» уровня проблемы, а не «как?» уровня реализации, повышает уровень абстракции. Если вы говорите: «Я выталкиваю элемент из стека, получая данные о самом последнем сотруднике», — абстракция может избавить вас от выполнения умственного эта- па «Я выталкиваю элемент из стека». Вы просто говорите: «Я получаю данные о самом последнем сотруднике». Эта выгода невелика, но если вы пытаетесь сокра- тить диапазон сложности, простирающийся от 1 до 10 9 , важен каждый шаг к цели. Использование именованных констант вместо литералов также повышает уровень абстракции. Объектно-ориентированное программирование обеспечивает уровень абстракции, относящийся одновременно и к алгоритмам, и к данным, который функциональная декомпозиция сама по себе обеспечить не может. Короче, главная цель проектирования и конструирования ПО — укрощение слож- ности. Снижение сложности лежит в основе многих методик программирования, и, наверное, его можно считать самым важным условием эффективного програм- мирования. 34.2. Анализируйте процесс разработки Вторая красная нить, проходящая через всю эту книгу, — подчеркивание на удив- ление большой важности используемого вами процесса разработки ПО. В неболь- шом проекте качество программы сильнее всего зависит от таланта конкретного программиста, а успешность программиста частично определяется используемыми им процессами. В проектах, реализуемых с участием более одного программиста, более важную роль играют организационные характеристики, а не индивидуальные навыки. Даже если у вас отличная группа, ее коллективная способность не эквивалентна сумме способностей отдельных членов. Именно способ совместной работы определяет, 820 ЧАСТЬ VII Мастерство программирования суммируются способности отдельных программистов или одна вычитается из дру- гой. Используемый группой процесс — вот от чего зависит, будет ли работа кон- кретного программиста повышать или понижать эффективность работы осталь- ных членов группы. Примером важности процесса разработки может служить обеспечение стабильности требований до начала проекти- рования и кодирования. Если вы не знаете, чтó создаете, вы не можете это хорошо спроектировать. Если требования, а позднее и проект, изменятся во время разработки, код тоже придется изменить, что может ухудшить качество системы. «Конечно, — скажете вы, — но в реальном мире требования никогда не бывают по-настоящему стабильными, поэтому данный пример неуместен». Опять-таки используемый вами процесс определяет, насколько стабильны ваши требования и насколько стабильными они должны быть. Если вы хотите сделать требования более гибкими, вы можете использовать инкрементную разработку, планируя поставить ПО заказчику несколькими частями, а не все сразу. Именно внимание к процессу и используемый вами процесс в конечном счете определяют успех или неудачу проекта. Данные табл. 3-1 (см. раздел 3.1), ясно говорят, что ошибки в требованиях гораздо дороже ошибок конструирования, поэтому концентрация на этой части процесса влияет также на стоимость и график выполнения проекта. Тот же принцип осознанного внимания к процессу справед- лив и для проектирования. Перед началом стройки нужно создать надежный фундамент. Если вы начнете писать код, не завершив создания фундамента, изменить архитектуру си- стемы будет труднее. Программисты будут дорожить уже написанным кодом. Трудно избавиться от плохого фунда- мента, если вы начали возводить на нем здание. Процесс разработки важен в первую очередь потому, что ка- чество должно встраиваться в ПО с самого начала. Это про- тиворечит давней «мудрости», согласно которой вы можете написать сколь угодно плохой код и устранить все ошибки на этапе тестирования. Это заблуждение. Тестирование может только указать на отдельные дефектные области программы — оно не сделает вашу программу удобнее в исполь- зовании, более быстрой, компактной, удобочитаемой или расширяемой. Преждевременная оптимизация — еще один изъян процесса разработки. Эффек- тивный процесс подразумевает, что вы выполняете грубую работу в начале и тонкую в конце. Если бы вы были скульптором, вы придавали бы композиции общую форму и только потом начинали бы работать над отдельными деталями. Преждевремен- но выполняя оптимизацию, вы тратите время на полирование фрагментов кода, которые полировать не нужно. Вы можете отполировать фрагменты, которые и так достаточно малы и быстры, вы можете отполировать код, который позднее придется выбросить, и можете отказаться от выбрасывания плохого кода, потому что уже потратили время на его полировку. Всегда спрашивайте себя: «Делаю ли я это в правильном порядке? Что изменилось бы при изменении порядка?» Исполь- зуйте адекватный процесс разработки и делайте это осознанно. Перекрестная ссылка Советы по повышению стабильности тре- бований см. в разделе 3.4, о различиях подходов к разработ- ке — раздел 3.2. Серьезным программистам я хочу сказать: уделяйте часть ра- бочего дня изучению и улучше- нию собственных методик. Хотя на программистов всегда давит какой-то будущий или прошед- ший крайний срок, методологи- ческая абстракция — мудрая долговременная инвестиция. Роберт У. Флойд (Robert W. Floyd) |