Создание, анализ ирефакторинг
Скачать 3.16 Mb.
|
11 G8: Слишком много информации . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 329 G9: Мертвый код . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 G10: Вертикальное разделение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 G11: Непоследовательность . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 330 G12: Балласт . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 G13: Искусственные привязки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 G14: Функциональная зависть . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 331 G15: Аргументы-селекторы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 332 G16: Непонятные намерения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 333 G17: Неверное размещение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 G18: Неуместные статические методы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 334 G19: Используйте пояснительные переменные . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 335 G20: Имена функций должны описывать выполняемую операцию . . . . . . . . . . . . 335 G21: Понимание алгоритма . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 336 G22: Преобразование логических зависимостей в физические . . . . . . . . . . . . . . . . 336 G23: Используйте полиморфизм вместо if/Else или switch/Case . . . . . . . . . . . . . . 338 G24: Соблюдайте стандартные конвенции . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 338 G25: Заменяйте «волшебные числа» именованными константами . . . . . . . . . . . . . 339 G26: Будьте точны . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340 G27: Структура важнее конвенций . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 340 G28: Инкапсулируйте условные конструкции . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 G29: Избегайте отрицательных условий . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 G30: Функции должны выполнять одну операцию . . . . . . . . . . . . . . . . . . . . . . . . . . . 341 G31: Скрытые временн*ые привязки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 342 G32: Структура кода должна быть обоснована . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343 G33: Инкапсулируйте граничные условия . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 343 G34: Функции должны быть написаны на одном уровне абстракции . . . . . . . . . . 344 G35: Храните конфигурационные данные на высоких уровнях . . . . . . . . . . . . . . . . 345 G36: Избегайте транзитивных обращений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 346 Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 J1: Используйте обобщенные директивы импорта . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 J2: Не наследуйте от констант . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 347 J3: Константы против перечислений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 348 Имена . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 N1: Используйте содержательные имена . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 349 N2: Выбирайте имена на подходящем уровне абстракции . . . . . . . . . . . . . . . . . . . . . 351 N3: По возможности используйте стандартную номенклатуру . . . . . . . . . . . . . . . . 352 N4: Недвусмысленные имена . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 352 N5: Используйте длинные имена для длинных областей видимости . . . . . . . . . . . 353 N6: Избегайте кодирования . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 353 N7: Имена должны описывать побочные эффекты . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 Тесты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 T1: Нехватка тестов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 T2: Используйте средства анализа покрытия кода . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 T3: Не пропускайте тривиальные тесты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 354 T4: Отключенный тест как вопрос . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 T5: Тестируйте граничные условия . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 T6: Тщательно тестируйте код рядом с ошибками . . . . . . . . . . . . . . . . . . . . . . . . . . . . 355 11 12 Содержание T7: Закономерности сбоев часто несут полезную информацию . . . . . . . . . . . . . . . . 355 T8: Закономерности покрытия кода часто несут полезную информацию . . . . . . 355 T9: Тесты должны работать быстро . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 Заключение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 Литература . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 356 Приложение А. Многопоточность II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357 Пример приложения «клиент/сервер» . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 357 Знайте свои библиотеки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 367 Зависимости между методами могут нарушить работу многопоточного кода . . . . . . 370 Повышение производительности . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 375 Взаимная блокировка . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 377 Тестирование многопоточного кода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 381 Средства тестирования многопоточного кода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 384 Полные примеры кода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 385 Приложение Б. org.jfree.date.SerialDate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 390 Приложение В. Перекрестные ссылки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 455 Эпилог . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 458 Алфавитный указатель . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 459 12 Предисловие В Дании очень популярны леденцы Ga-Jol . Их сильный лакричный вкус от- лично скрашивает нашу сырую и часто холодную погоду . Однако нас, датчан, леденцы Ga-Jol привлекают еще и мудрыми или остроумными высказываниями, напечатанными на крышке каждой коробки . Сегодня утром я купил две коробки леденцов и обнаружил на них старую датскую поговорку: Ærlighed i små ting er ikke nogen lille ting. «Честность в мелочах — вовсе не мелочь» . Это было хорошим предзнамено- ванием, которое полностью соответствовало тому, о чем я собирался написать в предисловии . Мелочи важны . Эта книга посвящена вещам простым, но вовсе не малозначительным . Бог скрывается в мелочах, сказал архитектор Людвиг Мис ван дер Роэ . Эта цитата напоминает о недавних дебатах о роли архитектуры в разработке программного обеспечения и особенно в мире гибких методологий . Мы с Бобом время от вре- мени увлеченно вступаем в этот диалог . Да, Мис ван дер Роэ проявлял внима- ние и к удобству, и к неподвластным времени строительным формам, лежащим в основе великой архитектуры . С другой стороны, он также лично выбирал каждую дверную ручку для каждого спроектированного им дома . Почему? Да потому, что мелочи важны . В наших с Бобом непрестанных «дебатах» о TDD выяснилось, что мы согласны с тем, что архитектура играет важную роль при разработке, хотя мы по-разному смотрим на то, какой смысл вкладывается в это утверждение . Впрочем, эти разногласия относительно несущественны, так как мы считаем само собой разумею щимся, что ответственные профессионалы выделяют некоторое время на обдумывание и планирование проекта . Появившиеся в конце 1990-х кон- цепции проектирования, зависящего только от тестов и кода, давно прошли . Тем не менее внимание к мелочам является еще более важным аспектом профессио- нализма, чем любые грандиозные планы . Во-первых, благодаря практике в ме- лочах профессионалы приобретают квалификацию и репутацию для серьезных про ектов . Во-вторых, даже мельчайшее проявление небрежности при строитель- стве — дверь, которая неплотно закрывается, или криво положенная плитка на полу, или даже захламленный стол — полностью рассеивает очарование всего 14 Предисловие 15 сооружения . Чтобы этого не происходило с вашими программами, код должен быть чистым . Впрочем, архитектура — всего лишь одна из метафор для разработки программ- ных продуктов . Она лучше всего подходит для проектов, в которых продукт «возводится» в том же смысле, в каком архитектор возводит строение . В эпоху Scrum и гибких методологий основное внимание уделяется быстрому выводу продукта на рынок . Фабрики, производящие программные продукты, должны ра- ботать на максимальной скорости . Однако этими «фабриками» являются живые люди: мыслящие, чувствующие программисты, работающие над пожеланиями пользователей или историей продукта для создания новых продуктов . Метафора производства сейчас как никогда сильна в их мировоззрениях . Скажем, методо- логия Scrum во многом вдохновлена производственными аспектами японского автостроения с его конвейерами . Но даже в автостроении основная часть работы связана не с производством, а с сопровождением продуктов — или его отсутствием . В программировании 80% и более того, что мы делаем, тоже изящно называется «сопровождением» . На самом деле речь идет о починке . Наша работа ближе к работе домашних ма- стеров в строительной отрасли или автомехаников в области автостроения . Что японская теория управления говорит по этому поводу? В 1951 году в японской промышленности появилась методология повышения качества, называвшаяся TPM (Total Productive Maintenance) . Она была ориен- тирована прежде всего на сопровождение, а не на производство . Доктрина TPM базировалась на так называемых «принципах 5S» . В сущности, принципы 5S представляют собой набор житейских правил . Кстати говоря, они также зало- жены в основу методологии Lean — другого модного течения на западной сцене, набирающего обороты и в программных кругах . Как указывает Дядюшка Боб в своем введении, хорошая практика программирования требует таких качеств, как сосредоточенность, присутствие духа и мышление . Проблемы не всегда ре- шаются простым действием, максимальной загрузкой оборудования для произ- водства в оптимальном темпе . Философия 5S состоит из следующих концепций: Сэйри, или организация . Абсолютно необходимо знать, где что находится — и в этом помогают такие методы, как грамотный выбор имен . Думаете, выбор имен идентификаторов неважен? Почитайте следующие главы . Сэйтон, или аккуратность . Старая американская поговорка гласит: всему свое место, и все оказывается на своих местах . Фрагмент кода должен на- ходиться там, где читатель кода ожидает его найти, — а если он находится где-то в другом месте, переработайте свой код и разместите его там, где ему положено быть . Сэйсо, или чистка . Рабочее место должно быть свободно от висящих проводов, грязи, мусора и хлама . Что в этой книге говорят авторы о загромождении кода комментариями и закомментированными строками кода? Они советуют от них избавиться . 15 16 Предисловие Сэйкэцу, или стандартизация: группа достигает согласия по поводу того, как поддерживать чистоту на рабочем месте . Что в этой книге сказано о наличии единого стиля кодирования и набора правил в группах? Откуда берутся эти стандарты? Прочитайте — узнаете . Сюцукэ, или дисциплина . Программист должен быть достаточно дисциплини- рованным, чтобы следовать правилам, он должен часто размышлять о своей работе и быть готовым к изменениям . Если вы не пожалеете усилий — да, усилий! — чтобы прочитать и применять эту книгу, вы научитесь понимать последний пункт . Мы наконец-то подошли к корням ответственного профессионализма в профессии, которая должна при- стально интересоваться жизненным циклом продукта . В ходе сопровождения автомобилей и других машин по правилам TPM, аварийный ремонт (аналог проявления ошибок) является исключением . Вместо этого мы ежедневно осма- триваем машины и заменяем изнашивающиеся части до того, как они сломаются, или выполняем аналоги знаменитой «смены масла каждые 10 000 миль» для предотвращения износа . Безжалостно перерабатывайте свой код . А еще можно сделать следующий шаг, который считался новаторским в движении TPM более 50 лет назад: строить машины, изначально ориентированные на удобство со- провождения . Ваш код должен не только работать, но и хорошо читаться . Как нас учит Фред Брукс, крупные блоки программного кода стоит переписывать «с нуля» каждые семь лет или около того, чтобы они не обрастали мхом . Но мо- жет быть, временную константу Брукса стоит вывести на уровень недель, дней и часов вместо годов . Именно на этом уровне живут мелочи . В мелочах кроется огромная сила, но при этом такой подход к жизни выглядит скромно и основательно, как мы стереотипно ожидаем от любого метода с япон- скими корнями . Однако такой взгляд на жизнь не является чисто восточным; в западной народной мудрости можно найти немало наставлений такого рода . Цитата, приведенная ранее при описании принципа сэйтон, принадлежит перу министра из Огайо, который буквально рассматривал аккуратность «как сред- ство от любого зла» . Как насчет сэйсо? Чистота ведет к Божественности . Каким бы красивым ни был дом, захламленный стол портит все впечатление . А что гово- рят о сюцукэ? Тот, кто верен в мелочах, верен во всем . Стремление к переработке кода, укрепление позиций для последующих «серьезных» решений — вместо того, чтобы откладывать переработку «на потом»? Ранняя пташка червяка ловит . Не откладывай на завтра то, что можно сделать сегодня . (Фраза «последний ответственный момент» в методологии Lean имела именно такой смысл, пока не попала в руки консультантов по разработке ПО) . Как насчет места малых, индивидуальных усилий в общей картине? Из маленьких желудей вырастают большие дубы . Интеграция простой профилактической работы в повседневную жизнь? Яблочко на ужин, и доктор не нужен . Дорога ложка к обеду . Чистый код уважает глубокие корни мудрости, лежащие в основе нашей культуры — той, ко- торой она когда-то была или должна быть, и может быть при должном внимании к мелочам . 16 Предисловие 17 Даже в литературе по архитектуре мы находим фразы, возвращающие нас к важ- ной роли мелочей . Вспомните дверные ручки ван дер Роэ . Сэйри в чистом виде . Внимание к имени каждой переменной . Имя переменной должно выбираться так же тщательно, как и имя новорожденного . Как известно любому домовладельцу, такая забота и непрерывное стремление к улучшению никогда не приходят к концу . Архитектор Кристофер Александр — отец паттернов и языка паттернов — рассматривает каждый акт проектирования как маленький, локальный акт восстановления . С его точки зрения мастерство тонкой структуры является единственным содержанием архитектуры; более крупные формы можно оставить на долю паттернов, а их применение — на долю жильцов . Проектирование продолжается не только с пристройкой к дому новых комнат, но и с покраской, заменой старых ковров или кухонной раковины . Ана- логичные принципы действуют во многих видах искусства . В поисках других мастеров, считавших, что Бог живет в мелочах, мы оказываемся в славной ком- пании французского писателя XIX века Гюстава Флобера . Французский поэт Поль Валери говорит о том, что стихотворение никогда не бывает законченным, что оно требует постоянной переработки, а прекратить работу над ним — значит бросить его . Такое повышенное внимание к мелочам характерно для всех настоя- щих творцов . Возможно, принципиального нового здесь не так уж много, но эта книга напомнит вам о необходимости следовать житейским правилам, которые вы давно забросили из безразличия или стремления к стихийности, к простой «реакции на изменения» . К сожалению, описанные аспекты редко рассматриваются как краеугольные камни искусства программирования . Мы рано бросаем свой код — и не потому, что он идеален, а потому, что наша система ценностей сосредоточена на внеш- нем виде, а не на внутренней сущности того, что мы делаем . Невнимательность в конечном итоге обходится недешево: фальшивая монета всегда возвращается к своему владельцу . Исследования — ни отраслевые, ни академические — не же- лают опускаться до скромной области поддержания чистоты кода . В те времена, когда я работал в Исследовательской организации по производству программного обеспечения Bell Labs, в ходе исследований выяснилось, что последовательный стиль применения отступов является одним из самых статистически значимых признаков низкой плотности ошибок . Мы хотим, чтобы причиной качества была архитектура, язык программирования или что-то другое, столь же почтенное . Нас как людей, чей предполагаемый профессионализм обусловлен мастерским владением инструментами и методами проектирования, оскорбляет сама идея, что простое последовательное применение отступов может иметь такую ценность . Цитируя свою собственную книгу 17-летней давности, скажу, что такой стиль отличает совершенство от простой компетентности . Японское мировоззрение сознает критическую важность каждого рядового рабочего, и что еще важнее — систем разработки, существующих благодаря простым повседневным действиям этих рабочих . Качество возникает в результате миллиона проявлений небезраз- личного отношения к делу, — а не от применения какого-то великого метода, 17 |