Чистый код. Создание, анализ и рефакторинг (Мартин)
1
Когда Игнац Земмельвейс в 1847 году впервые порекомендовал врачам мыть руки перед осмотром пациентов, его советы были отвергнуты на том основании, что у врачей слишком много работы и на мытье рук у них нет времени.
3
Из прощального послания Роберта Стивенсона Смита Баден-Пауэлла скаутам: «Постарайтесь оставить этот мир чуть лучшим, чем он был до вашего прихода…»
4
Как будет показано ниже, даже если контейнер действительно представляет собой List, лучше обойтись без кодирования типа контейнера в имени.
5
Для примера можно привести совершенно отвратительную привычку создавать переменную klass только из-за того, что имя class было использовано для других целей.
6
Дядюшка Боб действовал так при программировании на C++, но потом бросил эту привычку, потому что благодаря современным IDE она стала излишней.
8
«Святая ручная граната» — оружие огромной разрушительной силы из фильма «Монти Пайтон и Священный Грааль». — Примеч. перев.
9
Из мультипликационного сериала «Симпсоны». — Примеч. перев.
10
Тестовая программа, распространяемая с открытым кодом — www.tnese.org.
11
Программа модульного тестирования для Java, распространяемая с открытым кодом — www.junit.org.
12
Я спросил Кента, не сохранилась ли у него эта программа, но ему не удалось ее найти. Обшарил все свои старые компьютеры — тоже безуспешно. Остались лишь мои воспоминания об этой программе.
13
В языке LOGO ключевое слово TO использовалось так же, как в Ruby и Python используется «def». Таким образом, каждая функция начиналась со слова «TO».
14
Разумеется, сюда же относятся и длинные цепочки if/else.
15
http://en.wikipedia.org/wiki/Single_responsibility_principle; http://www.objectmentor.com/resources/articles/srp.pdf.
16
http://en.wikipedia.org/wiki/Open/closed_principle; http://www.objectmentor.com/resources/articles/ocp.pdf.
17
Я только что завершил переработку модуля, использовавшего бинарную форму. Мне удалось преобразовать outputStream в поле класса и привести все вызовы writeField к унарной форме. Результат получился гораздо более наглядным.
18
Люди, считавшие, что они смогут обойтись без перекомпиляции и повторного развертывания, были пойманы и сурово наказаны.
19
Пример принципа открытости/закрытости (OCP) [PPP02].
20
Принцип DRY [PRAG].
21
[KP78], p. 144.
22
Прямоугольник представляет диапазон «сигма/2» выше и ниже среднего значения. Да, я знаю, что распределение длин файлов не является нормальным, поэтому стандартное отклонение не может считаться математически точным. Но я и не стремлюсь к точности. Я хочу лишь дать представление о происходящем.
23
Кого я пытаюсь обмануть? Я так и остался ассемблерным программистом. Парня можно разлучить с «металлом», но в душе «металл» все равно живет!
24
У проблемы существуют обходные решения, хорошо известные опытным объектно-ориентированным программистам: например, паттерн ПОСЕТИТЕЛЬ или двойная диспетчеризация. Но у этих приемов имеются собственные издержки, к тому же они обычно возвращают структуру к состоянию процедурной программы.
26
Иногда это называется «функциональной завистью» (Feature Envy) — из [Refactoring].
27
См. описание паттерна АДАПТЕР в [GOF].
28
Professionalism and Test-Driven Development, Robert C. Martin, Object Mentor, IEEE Software, May/June 2007 (Vol. 24, No. 3), pp. 32–36; http://doi.ieeecomputersociety.org/10.1109/MS.2007.85
30
См. «Избегайте мысленных преобразований», с. 47.
31
См. запись в блоге Дейва Астела (Dave Astel): http://www.artima.com/weblogs/viewpost.jsp?thread=35578.
32
Учебные материалы Object Mentor.
33
За более подробной информацией об этом принципе обращайтесь к [PPP].
34
Например, см. [Fowler].
35
См. [Spring] и описание Spring.NET.
36
Не забывайте, что отложенная инициализация — всего лишь разновидность оптимизации… и возможно, преждевременная!
37
Система управления базами данных.
38
За общей информацией об аспектах обращайтесь к [AOSD], а за конкретной информацией об AspectJ — к [AspectJ] и [Colyer].
39
То есть без необходимости ручного редактирования целевого кода.
40
См. [CGLIB], [ASM] и [Javassist].
41
Более подробные примеры API посредников и его использования можно найти, например, в [Goetz].
42
Методологию АОП иногда путают с приемами, используемыми для ее реализации например перехватом методов и «инкапсуляцией» посредников. Подлинная ценность АОП-системы заключается в способности модульного, компактного определения системного поведения.
43
См. [Spring] и [JBoss]. «Непосредственно на уровне Java» в данном случае означает «без применения AspectJ».
45
Приведенный пример можно упростить — существуют специальные механизмы, использующие правила конфигурации и аннотации Java 5 для сокращения объема явно определяемой «связующей» логики.
46
По материалам http://www.onjava.com/pub/a/onjava/2006/05/17/standardizing-with-ejb3-java-persistence-api.html.
47
См. [AspectJ] и [Colyer].
48
Не путайте с полезной практикой упреждающего проектирования. BDUF — привычка проектировать заранее все без исключения, до написания какого-либо кода реализации.
49
Впрочем, даже после начала строительства идут серьезные итеративные исследования и обсуждения подробностей.
50
Выражение «физика программного продукта» впервые было использовано в [Kolence].
51
Работа [Alexander] оказала особенно заметное влияние на сообщество разработчиков ПО.
52
Например, см. [DSL]. [JMock] — хороший пример Java API, создавшего свой предметно-ориентированный язык.
53
Фазы Луны, космические лучи и т.д.
54
См. раздел «Копаем глубже» на с. 364.
55
См. раздел «Пути выполнения» на с. 262.
56
См. раздел «Пример архитектуры «клиент/сервер»» на с. 357.
57
Также встречается термин «активная блокировка». — Примеч. перев.
61
См. раздел «Зависимости между методами могут нарушить работу многопоточного кода», с. 370.
62
«Критической секцией» называется любой фрагмент кода, который должен быть защищен от одновременного использования несколькими программными потоками.
63
См. раздел «Увеличение производительности», с. 375.
64
См. раздел «Взаимная блокировка», с. 377.
65
А вы знаете, что потоковая модель Java не гарантирует вытесняющей многопоточности? В большинстве современных ОС поддерживается вытесняющая многопоточность, которую вы фактически получаете автоматически. И все же JVM ее не гарантирует.
66
Строго говоря, это не совсем так. Поскольку JVM не гарантирует вытесняющей многопоточности, конкретный алгоритм может всегда работать в ОС, не поддерживающей вытеснения. Обратное тоже возможно, но по другим причинам.
68
Недавно я переписал этот модуль на Ruby. Код занимает в 7 раз меньше места и имеет более качественную структуру.
69
Чтобы предотвратить подобные сюрпризы в будущем, я добавил новый модульный тест, который запускал все тесты FitNesse.
70
JUnit Pocket Guide, Kent Beck, O’Reilly, 2004, c. 43.
71
См. раздел «Правило бойскаута» на с. 37.
72
А еще правильнее было бы считать в Javadoc все комментарии заранее отформатированными, чтобы они одинаково смотрелись в коде и в документации.
74
А конкретно — принцип единой ответственности, принцип открытости/закрытости и принцип сокрытия реализаций. См. [PPP].
75
Знать, как работает ваш код, и знать, делает ли алгоритм то, что требуется, — не одно и то же. Не уверены в правильности выбора алгоритма? Нередко это суровая правда жизни. Но если вы не уверены в том, что делает ваш код, то это обычная лень.
76
См. цитату Уорда Каннингема на с. 34.
77
[DDD].
78
Вы можете убедиться в этом сами, тестируя код до и после внесения изменений. Однопоточный код приведен на с. 385, а многопоточный – на с. 389.
79
Это несколько упрощенное объяснение. Впрочем, для целей нашего обсуждения мы воспользуемся этой упрощенной моделью.
80
На самом деле интерфейс Iterator в принципе не обладает потоковой безопасностью. Он не проектировался с расчетом на многопоточное использование, так что этот факт не вызывает удивления.
81
Кто-то добавляет отладочный вывод, и проблема «исчезает». Отладочный код «решил» проблему, поэтому он остается в системе.