Брутально и бессердечно о программировании и проектировании
ГлавнаяФорумПаттерныАнтипаттерныТест-драйвЗаметкиВопрос-ответКнигорецензииСправочная

23. Венгерская нотация

Самое идиотское изобретение человечества после фонарика на солнечных батарейках, это, конечно же, венгерская нотация. Однако, к сожалению, этот факт до сих пор не является очевидным для многих разработчиков. Поговорим о венгерской нотации и создаваемых ею проблем более детально.
 
Лишняя информация
Информация о точном типе переменной в ее имени — это лишняя информация. Любая лишняя информация сбивает пользователя с толку, и он начинает думать не о том, о чем должен. Конечно же, некоторая информация о типе пользователю все же может понадобиться, однако речь идет далеко не о том, является ли тип указателем на void, или же это строка в стиле Plain C.
Во-первых, пользователю может понадобиться информация о размере переменной или объекта. С этой задачей прекрасно справится оператор sizeof.
Во-вторых, пользователю нужно знать, является ли языковая сущность единичным объектом, или же это множество объектов, то есть контейнер. И не просто контейнер, а контейнер в человеческом понимании. То есть, std::string — единичный объект.
Вся остальная информация является лишней. Если же для понимания программы пользователю все-таки требуется какая-то дополнительная информация, касающаяся типа той или иной сущности, то это просто означает, что система, с которой работает пользователь, плохо спроектированна, а предоставляемые сущности имеют плохие имена, не соответствующие формуле «Именование = назначение = использование».
 
Замена типа
Венгерская нотация создает массу проблем после любой замены типа. Любая замена типа в лучшем случае приведет к куче ошибок времени компиляции. В худшем — неочевидных и не всегда легко выявляемых ошибок времени выполнения.
Во-первых, может просто возникнуть необходимость заменить один тип данных на другой. В этом случае придется ползать по всем исходникам и вносить исправления во все места, где успел «засветиться» объект или переменная.
Во-вторых, если проект компилируется под несколько платформ, то тип данных, который на одной платформе является DWORD-ом, на другой платформе может оказаться уже QWORD-ом, а следовательно информация, содержащаяся в имени переменной уже не будет соответствовать действительности.
Помимо всего прочего, попробуйте отвлечься от языка C++ и подумайте, каковы будут последствия замены типа в языках, не имеющих статической типизации.
 
Отсутствие контроля
Однако главный недостаток венгерской нотации заключается в том, что она является искусственным правилом, а не частью языковой грамматики. Например, никто не мешает взять переменную типа BYTE и назвать ее ulSize. Компилятору совершенно все равно — проверка этих соответствий не входит в круг его полномочий. В этом случае информация о типе будет являться не только лишней, но еще и не соответствующей действительности. По сути, разработчики, использующие венгерскую нотацию, переносят работу по контролю типов с плечь компилятора на свои собственные. Это один из ярких примеров того, как человек из-за сиюминутного удобства берется решать задачи, с которыми может прекрасно справиться машина. Использование всяческих префиксов и суффиксов по сути не дает никаких гарантий, по сути претупляя бдительность пользователя и давая ему еще один шанс допустить ошибку.
 
Мотивация
В реальной жизни все же существуют задачи, когда пользователю действительно нужна полная информация о типе. Например, передача данных на внешнее устройство — мы хотим точно быть уверены в том, что данные передаются именно по байтам. Или же — вычисление контрольной суммы — нам нужна четкая гарантия того, что работа с числами идет по правилам беззнаковой арифметики. В таких случаях нужно создать всяческие защитные механизмы, как уровня компиляции, так и уровня выполнения, которые позволят дать гарантиют того, что работа с объектами и переменными идет согласно с предъявляемыми требованиями. Как вы понимаете, простое добавление префиксов в имена не дает абсолютно никаких гарантий. Вопрос производительности защитных механизмов решается элементарно. Для механизмов уровня компиляции, очевидно, этот вопрос не стоит вообще; механизмы же уровня выполнения реализуются, как вариант, следующим образом:
0
1
2
3
4
5
6
7
8
9
10
class safe_byte
{
    // Реализация (в том числе всей арифметики)
    // со всевозможными проверками
};

#if defined (debug)
typedef safe_byte byte;
#else
typedef unsigned char byte;
#endif // debug
 
Завязка на размер
Существуют ситуации, когда нужны четкие гарантии относительно размера типа. Чаще всего такие ситуации возникают, когда возникает необходимость обмениваться данными внутри системы, в которой каждый участник общения может быть скомпилирован под разные платформы. Например — сетевой маршрутизатор, общающийся по своему внутреннему протоколу с себеподобными, скомпилированный как под 32, так и под 64 бита.
В таком случае стоит ввести специальный набор типов данных, из которых будут собираться пакеты для общения с себеподобными и для которых имеется некоторый механизм или гарантия обеспечения целостности размера данных, независимо от платформы. Этот набор типов нужно использовать как можно более локально и только по назначению, не позволяя им выбираться куда-то на поверхность и решать какие-то задачи, не связанные с cross-application взаимодействием. Набор данных, о которых идет речь, мог бы выглядеть следующим образом:
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace network
{

namespace detail
{

#if defined (platform_16)
typedef unsigned char      byte;
typedef unsigned int       word;
typedef unsigned long int  dword;
#elif defined (platform_32)
typedef unsigned char      byte;
typedef unsigned short int word;
typedef unsigned int       dword;
#elif defined (platform_64)
typedef unsigned char      byte;
typedef unsigned short int word;
typedef unsigned int       dword;
#else
#error Unknown platform
#endif

} // namespace detail

} // namespace network
 
Заключение
Очевидно, существует множество способов, как уровня компиляции, так и уровня выполнения, позволяющих выстроить определенные защитные механизмы, дающие гарантии того, что определенный набор данных отвечает определенным правилам поведения — ограничением здесь выступает практически лишь фантазия и квалификация разработчика. Надеюсь, что столь же очевидно и то, что искусственные приемы вроде венгерской нотации не дают аюсолютно никаких гарантий и, в действительности, не решают тех задач, которые ошибочно перед ними ставятся.

Оглавление
Статистика
© 2007—2009 Inside C++ Коммерческие услугиКонтактная информация

Качественные в киеве о мобильных о телефоне по супер-цене. строительные вагончики волгоград . Где найти квесты?. Продаем офисные стулья и кресла в Казани.