* При перепечатке материалов ссылка на www.SeoLiga.ru обязательна! RSS



Анти-паттерны в действии или Самые популярные ошибки программистов
6 февраля 2009

Большинство книг, статей и тем более ответы на форумах вводят начинающих программистов в глубокое заблуждение по поводу того, как следует программировать. Даже если автор кусочка кода пишет про его недостатки и явно указывает на "учебный"(не в смысле того, что по нему надо учиться писать код) характер кода, то на это всё равно мало кто обращает внимание. В этой статье мы рассмотрим наиболее распространённые ловушки программирования, которые наши западные коллеги назвали анти-паттернами. В отличие от правильных проектных решений, называемых паттернами, анти-паттерны ведут код к путанице и полному отсутствию гибкости и масштабируемости. Начинающие программисты, у которых ещё не выработался иммунитет к анти-паттернам, испытывают практически непреодолимое желание их использовать и проваливаются с головой в приготовленную ловушку.
Итак, рассмотрим 20 наиболее распространённых по моему мнению антипаттернов:
1) Магические числа
Магические числа - это числовые значения, встечающиеся в исходном тексте, приэтом неочевидно, что они означают. Данный антипаттерн затрудняет понимание программы и усложняет ее рефакторинг.
Например,
0: drawEllipse(125, 55, 25, 37, 12.5);

Магические числа необходимо выносить в константы, реже в переменные с внятными именами и комментарием при объявлении.
Например, вышеуказанный код следует переписать в виде:
0: const int xC = 125; // координаты центра
const int yC = 55; // эллипса
const int a = 25; // большая полуось
const int b = 37; // малая полуось
const float phi = 12.5; // угол поворота эллипса против часовой стрелки в градусах
...
drawEllipse(xC, yC, a, b, phi);

Однако надо учесть, что не все числа являются магическими, если предназначения чисел очевидно, то их не надо заменять константами, классический пример:
0: for (int i:=0; i<сount; i++) ... ;

2) Магические строки
Аналог предыдущего антипаттерна для строк; не всегда понятно, что означает тот или иной строковый литерал, к тому же если он поменяется, то проблемы не заставят себя долго ждать...
Классический пример - имя файла, например, с настройками приложения.

3) Магическая кнопка
Этот анти-паттерн сверхпопулярен, особенно среди програмистов на Delphi, .NET и VB. Он заключается в том, что логика приложения сосредоточена в обработчиках событий, типа OnClick и все остальные. В корректно написаных программах в обработчиках событий значится лишь вызов нужного метода, что позволяет гибко менять пользовательский интерфейс и даже менять библиотеку виджетов без всяких проблем. Все нормальные люди разделяют пользовательский интерфейс и логику работы самой программы. А "Магическая кнопка" — это внедрение логики работы программы в пользовательский интерфейс. Зачем это делается? Как всегда — из-за лени. Так легче решить сиюминутную проблему.
Чтобы не поддаться соблазну запомни золотое правило: В любом обработчике события не должно быть больше пяти строк кода!

4) Ненужная сложность
Сложность, которая возникает в коде, приэтом она не является необходимой для решения текущей проблемы. В то время как существенная сложность - свойственна и неизбежна, ненужная сложность вызвана подходом, неверно выбранным для решения проблемы. Ненужная сложность должна быть минимизирована в любой хорошей архитектуре и решении, чрезмерная ненужная сложность - яркий пример анти-паттерна.
Чтобы избежать чрезмерной ненужной сложности необходимо чётко следовать принципу "Всё должно быть сделано настолько простым, насколько это возможно, но не проще" (с) А.Эйнштейн. или его более ранней формулировке - бритве Оккама

5) Слепая вера
Недостаточная проверка:
a) корректности исправления ошибки, т.е. пренебрежение процедурой тестирования
b) результата работы подпрограммы, т.е. провальная передачи неверного результата
с) пользовательского ввода. а это вообще хит, запомни всё что ввёл пользователь должно проходить максимально жёсткую проверку!
Запомни, в программировании, как и в жизни, нельзя никому верить. Тебя могут обмануть на каждом шагу. Считай все данные, с которыми ты работаешь, априори некорректными!

6) Лодочный якорь
Сохранение более не используемой части системы, т.е. ты не хочешь удалять некоторый код, который уже не используется(закомментирован) или даже недосягаем(не выполняется ни при каких условиях, например, if (1==2) { недосягаемый_код }), в надежде что возможно он тебе когда-нибудь пригодится и вообще не зря же ты тратил время на его написание
Приводит к замусориванию кода; неиспользуемый код необходимо удалять, если он тебе дорог или есть к-л сомнения, то сделай резервную копию, а ещё лучше - пользуйся системой управления версиями, типа Subversion.

7) Активное ожидание
Потребление процессорного времени во время ожидания события, обычно при помощи постоянно повторяемой проверки, вместо того, чтобы использовать систему сообщений.
Пользуйся механизмом событий вместо циклов с проверкой, тогда ты не попадёшь в эту ловушку.

8 ) Кодирование путём исключения
Этот антипаттерн представляет собой реализацию нормальной логики работы программы с помощью механизма исключений. Например, рекурсивный поиск по дереву может в качестве результата поиска кидать исключение. Такая реализация на первый взгляд может выглядеть заманчиво и удобно, но не более чем на первый взгляд.
Исключения должны использоваться с одной единственной целью — проинформировать систему об ошибке. Использование исключений как инструмента для управления логикой программы вносит неоднозначность. Глядя на конструкцию try-throw-catch / try-raise-except, программисту совершенно не очевидно, для чего именно эта конструкция используется. Кроме того, управление логикой через исключения и система оповещения об ошибках, построенная на исключениях, могут попросту мешать друг другу, поскольку они построены на одном механизме.
Для обработки ошибок используйте только исключения, а исключения — только для обработки ошибок.

9) Таинственный код
Использование неизвестных аббревиатур вместо полных(самоописывающих) имён.
Запомни, из имён функций, переменных, классов, etc. должно быть понятно зачем они нужны и за какие действия ответсвенны. Не экономь символы, все современные редакторы поддерживают возможность подсказок/завершения ввода на основе нескольких первых символов идентификатора, однако не надо ударяться в другую крайность - слишком длинные имена, постарайся ограничиться 20 символами.

10) Процедурный код
Использование процедурной/структурной парадигмы во всех случаях жизни, - частный случай "золотого молота" для новичков.
Запомни, следует использовать ту парадигму, которая лучше подходит для решения конкретной задачи. При этом процедурная парадигма в наше время подходит лишь для учебных программ, поэтому и является антипаттерном.

11) Спагетти-код
Этот антипаттерн излюблен программистами, для которых существует всего один критерий качества программы — «Программа работает».
«Спагетти» — так называется расползание кода на одном уровне программы. Для этого антипаттерна характерны функции очень большого размера, зачастую с обилием неочевидных ветвлений и безусловных переходов.
Старайтесь программировать так, чтобы размер ваших функций не превышал 15-25 строк, ну или хотя бы чтобы функция целиком помещалась на одном экране.

12) Программирование методом Copy & Paste
Допустим, тебе нужно написать две похожие функции. Ты пишешь первую функцию, потом «Копировать» — «Вставить», и вносишь необходимые изменения. Знакомая ситуация? Если да, то срочно избавляйся от этой привычки!
Такая методология программирования несет следующие проблемы. Во-первых, отсутствие декомпозиции. Если придется что-то менять, то придется менять во всех местах, куда «накопипастил». Во-вторых, после копирования, программист частенько забывает внести в копию полностью все изменения.
Данный антипаттерн является источником самых неприятных ошибок, так как он противоречит самым основам программирования.

13) Преждевременная оптимизация
Существует один железобетонный аргумент, превращающий преждевременную оптимизацию из паттерна в антипаттерн: в абсолютном большинстве случаев оптимизация происходит в жертву красоте решения, а именно в жертву универсальности, инкапсуляции, переносимости, возможности повторного использования и т.д. Любой из перечисленных аспектов несравнимо дороже производительности.
Пока код не дописан, можно выполнять лишь высокоуровневую оптимизацию, т.е. оптимизацию уровня алгоритма. А оптимизацией конкретных участков кода следует заниматься только в случаях крайней необходимости, и только после того, как оптимизируемый инструмент полностью готов к работе, а оптимизируемый участок кода жестко инкапсулирован от всего окружающего мира. Причём перед оптимизацией необходимо выполнить профайлинг уже работающего кода для выявления самых медленных мест, потому что как бы ты не гордился тем, что ты знаешь как оптимизировать некоторый участок кода, если он выполняется всего 1 раз, то в большинстве случаев тратить на него время не имеет никакого смысла.

14) Преждевременная пессимизация
Является обратной крайностью антипаттерна "Преждевременная оптимизация". Преждевременная пессимизация - это целенаправленное использование приемов, явно снижающих производительность. Например, передача объектов в функцию по значению, а не по константной ссылке.
Старайтесь, чтобы вас не кидало в стороны, следуйте оптимальным (оптимальным, а не оптимизированным) решениям, и, конечно же, здравому смыслу. Старайтесь находить золотую середину. Решение должно быть максимально оптимально, но ни в коем случае не за счет своей красоты и изящества.

15) Изобретение велосипеда
Смысл антипаттерна состоит в том, что программист разрабатывает собственное решение, в то время как существуют не менее, а зачастую и более достойные аналоги.
Этот антипаттерн особенно свойственен русской душе. Каждый считает себя самым-самым, и отвергает саму возможность того, что кто-то способен решить эту задачу лучше, чем он сам.
Каким бы талантливым программистом ты не был, изобретение велосипеда этот как минимум трата времени, а время, как известно — самый ценный ресурс.

16) Изобретение велосипеда c квадратными колесами
Расширенный случай предыдущего антипаттерна, в данном случае программист плохо разбирается в теме, для которой пишет "велосипед" и как следствие его решение не выдерживает никакого сравнения с существующими известными аналогами.

17) Божественный класс/объект
Это класс, на который возложено слишком много обязанностей. Каждый класс должен иметь одно конкретное назначение, которое можно описать несколькими словами. Большие классы тяжело поддерживать, они очень неповоротливы и трудны для рефакторинга. Лучше пять маленьких классов, решающих конкретные задачи, чем один большой и универсальный класс.

18 ) Базовый класс-утилита
Наследование функциональности из класса-утилиты вместо делегирования к нему. Классы-утилиты - это своеобразные помощники, выполняющие некоторую вспомогательную функциональность. Наследовать от него один из основных(не вспомогательных) классов - неудачная идея!

19) Хардкодинг
Данный антипаттерн подразумевает жесткое «вшивание» в программный код различных данных, касающихся окружения программы. Например, это могут быть: путь к файлу конфигурации, имя почтового сервера, имя процесса, с которым взаимодействует программа, и так далее. Этот список можно продолжать бесконечно. Одни словом — «захардкодить» означает прописать значение каких-либо данных непосредственно в коде, вместо того, чтобы передавать их в качестве параметра.
Хардкодинг несет в себе скрытую опасность. На компьютере разработчика программа будет прекрасно работать, но стоит ее только перенести на новую систему, как программа потеряет свою работоспособность. Хардкодинг невозможно выявить на машине разработчика без досконального изучения кода, и поэтому, если программист захардкодил какие-то значения (и, как правило, забыл, где он это сделал), то такая программа будет иметь совершенно непредсказуемое поведение, а сложность выявления и локализации ошибок станет невероятно высокой.

20) Гонки
Ошибка в определении последовательности различных порядков событий. Например, OnActivate, OnCreate, OnPaint, OnShow. Ты должен быть либо абсолютно уверен в каком порядке будут вызваны события, либо не строить предположений относительно этого в коде(например, не стоит создавать объект в OnShow, а обращаться к нему в OnCreate). Ещё лучше, вовсе не связывать код из различных событий...

21) Накопить и запустить
Установка параметров подпрограмм в наборе глобальных переменных.

22) Ползущий улучшизм
Добавление новых улучшений в ущерб качеству системы.
Запомни, лучше реализовать 50% функций на 100%, чем 100% функций на 50%.

23) Золотой молот
Золотой молот - это применение какого-то конкретного паттерна для решения всех возможных и невозможных задач. Программист «влюбляется» в какой-то паттерн, и начинает использовать его где только это возможно, как универсальное решение всех проблем, как золотой молот.
Помимо профессиональных программистов, золотой молот также встречается среди новичков. Однако, в этом случае его причины иные — новичку просто лень изучать что-то новое, и он пытается решать все задачи единственным методом, который он освоил.

24) Программирование методом подбора
Подбора параметров, токенов, порядка и наличия вызовов функций, и так далее. «Попробуем так… Не работает… А есть так… Во, так вроде ничего».
Программирование методом подбора устраняет только видимую часть ошибки и не дает программисту понимания сути происходящего.

25) Дым и зеркала
Демонстрация того, как будут выглядеть ненаписанные функции. Излюбленное занятие маркетологов, программистам же так себя вести просто неприлично. Попало в этот список, так как на форуме был реальный пример использования этого антипаттерна - vr-online.ru/topic.php?id=10950

P.S. Данный список антипаттернов не претендует на полноту, на самом деле их гораздо больше, однако, невошедщие в обзор, антипаттерны менее характрены для начинающих программистов, т.к. учитывают специфику командной разработки, тонкости ООП и неправильное применение паттернов, с которыми новички попросту не сталкиваются. Так что даже опытные программисты наступают на грабли, но это уже совсем другие грабли...


Теги: .NET

Статьи по теме:

Модификаторы доступа для вложенных типов
Специальные возможности и элементы управления Windows Forms
Императивная защита по правам доступа к коду
Редактор реестра
Связывание, просмотр и фильтрация данных
Редактор типов файлов
.NET Framework и языки программирования
Получение доступа к библиотекам типов .NET и СОМ
Операторы Imports и using
Интерфейсы CTS
Компонент ErrorProvider
Рекурсия
Towards Cleaner Code, A C# Asynchronous Helper
Cosmos – C# Open Source Managed Operating System
Разрешения
| .NET | Pavel |
 


Пн Вт Ср Чт Пт Сб Вс
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31


     



Rambler's Top100

Данный сайт или домен продается ICQ: 403-353-727

© 2009 Seoliga.ru | .NET | Анти-паттерны в действии или Самые популярные ошибки программистов. Регион сайта: Москва и Санкт-Петербург