Является ли система венгерской нотации полезной практикой? [закрыто]

23

Я искал форум, но я не мог найти ответы, почему этого следует избегать, только почему это не серебряная пуля. Поэтому я не думаю, что этот вопрос является дубликатом.

Есть ли ДЕЙСТВИТЕЛЬНАЯ причина, почему я должен отучиться от венгерского языка Systems, к которому я привык?

До сих пор я вижу следующие преимущества в его использовании:

  • Согласованное именование переменных
  • Вы видите тип без поиска (intellisense не работает / индексирует половину времени, поэтому это все еще веская причина)
  • Семантика все еще может быть упакована во вторую часть имени

И следующие недостатки:

  • Это раздражает некоторых людей (понятия не имею, почему)
  • Если тип изменен, тип может не соответствовать названию переменной (я не думаю, что это правильная причина, типы меняются редко, и у вас есть «переименовать все»)

Так почему:

vector<string> vecCityNames;
wstring strCity = L"abc";
//more code here
vecCityNames.push_back(strCity);

хуже чем:

vector<string> cityNames;
wstring city = L"abc";
//more code here
cityNames.push_back(city);//Are we pushing back int on a queue? Float on a stack? Something else?
кодировщик
источник
4
если intellisense не работает, ваш код недействителен. Если это неверно, зачем считать, что имя переменной правильное?
Bubblewrap
6
@Bubblewrap: большинство реализаций intellisense иногда теряются в течение 3 секунд, даже для действующего кода. И иногда они вообще не работают, даже если код компилируется и ссылается. Мы говорим о разумных размерах проектов.
Кодер
9
не должно vectCityNamesбыть vectStringCityNamesтак много для вашего последовательного аргумента, и этот «вопрос» - скорее разглагольствование, чем что-либо еще, вы должны принять решение, это должно быть закрыто.
8
Что вы считаете «уважительной» причиной?
Адам Лир
15
Я не думаю, что ваш второй пример сбивает с толку то, как ваш комментарий указывает на это. Смысл cityNames.push_back(city)довольно понятен. Это список названий городов, и вы добавляете его.
Крис Бёрт-Браун

Ответы:

62

Я использовал его (много лет назад) и больше не пользуюсь. Основная причина в том, что в ОО-языках со строгой типизацией (C ++, Java) излишне, что я использовал большую часть своей карьеры. В этих языках, если я правильно определю свои типы, компилятор может и будет обеспечивать безопасность типов для меня. Таким образом, любые префиксы именования являются просто беспорядком, который делает имена длиннее, что затрудняет чтение и поиск.

В любой хорошо написанной ОО-программе большинство ваших переменных являются (ссылками) пользовательских типов. Если вы добавите к ним префикс тем же общим тегом (например, oдля «объекта»), вы не получите никакой выгоды от него, только от недостатков. Однако, если вы добавите к ним префиксы с помощью специфических для типа тегов, вы попадаете в лабиринт, пытаясь найти разные сокращения для тысячи различных типов с часто похожими именами * и не забудьте изменить их все при изменении типа или его имени (что является совсем не редкость в ухоженной программе).

Конечно, это не относится к языкам, не относящимся к ОО, и может не относиться к языкам со слабой и / или динамической типизацией (у меня нет опыта работы с ними, кроме C). Ни к неоптимальным редакторам / IDE без полезного IntelliSense (или его локального эквивалента). И это только мои 2 цента. Так что, если венгерская нотация работает для вашей команды и вашего проекта, сделайте это. Важно договориться об этом (а также о согласованном стиле кодирования в целом) до начала проекта и всегда поддерживать его в согласованном состоянии.

* Только короткий список из нашего текущего проекта: у нас есть Charge, ChargeBreakdown, ChargeCalculator, ChargeDAO, ChargeDTO, ChargeLineHelper, ChargeMaps, ChargePairи ChargeType, среди прочих. Более того, у нас также есть Contracts, Countries, Checkouts, Checkins ... и это просто буква C в проекте, который, возможно, даже не будет назван OP "разумного размера".


Отказ от ответственности: я на самом деле венгр, поэтому я считаю, что могу говорить по этому вопросу с авторитетом ;-)

Петер Тёрёк
источник
«Строгая типизация». Если бы в C ++ была действительно сильная система типов, вам не пришлось бы встраивать типы в имя переменной как хак.
Майкл Бёрдж,
19
@MichaelBurge: в этом все дело. Вам не нужно. Потому что это так.
DeadMG
8
+1 за балл о пользовательских типах. Использование именованных iPosили fAmountдопустимых переменных , но попробуйте поработать над базой кода, где каждой переменной объекта присваивается избыточный шестибуквенный префикс, информирующий вас только о том, что это «указатель на структуру».
2
Я бы сделал исключение для графического интерфейса, где вам нужно хранить дескриптор для каждого элемента управления в дополнение к его значению, поэтому текст и hText вместо того, чтобы придумывать другое имя для поля ввода. Особенно важно в системах, где дескриптор - просто int, а не специальный тип.
Мартин Беккет
1
Я бы сказал, что главное место, где Java должна была бы рекомендовать использование венгерской нотации, - это различать ссылки на экземпляры, которые могут быть видоизменены, но никогда не переданы (например, char[]удерживаемые a StringBuilder), и ссылки на экземпляры, которые не могут быть видоизменены, но может использоваться совместно с вещами, которые не изменяют их (например, char[]удерживается String, который может совместно использоваться несколькими Stringэкземплярами). Оба поля одного типа char[], но они содержат вещи, которые сильно различаются. Много ошибок, связанных с
изменчивостью,
35

Почему std::vector<string> vecCityNames;плохо?

Проблема с венгерской нотацией, поскольку она обычно используется, заключается в том, что, если профилирование показывает, что названия городов лучше хранить в a std::deque, все имена переменных, относящиеся к объекту этого типа, внезапно будут иметь неверное имя.

Вы собираетесь переименовать все ваши переменные? Вы когда-нибудь пытались сделать это в большом проекте? С помощью Мерфи (а парень невероятно полезен там) кто-то наверняка использовал переменные, называемые чем-то вроде deqCityNames, заставляя ваши изменения ломать сборку, заставляя вас часами возиться с кодом, который в течение полувека никто не осмеливался даже смотреть из-за страха быть укушенным ядовитым зверем.

Из того, что я знаю, однако, то, как Чарльз Симони придумал венгерский, префикс обозначал семантическое использование переменных , а не их синтаксический тип . Таким образом, правильный префикс для вашего списка названий городов, независимо от того, в каком типе он реализован, вероятно, будет listCityNames(или lstCityNames, если listне достаточно загадочным для вас).

Но я считаю этот префикс довольно излишним, потому что множественное число («имена») уже передает, что это группа городов. Итог: когда вы тщательно выбираете свои идентификаторы, венгерские обозначения редко нужны. OTOH, способ, которым это обычно используется, это, в конечном счете, фактически наносит ущерб коду.

SBI
источник
6
@Coder: тип используется во всем проекте, и все переменные этого типа будут иметь префикс. Вам придется переименовать не одну глобальную переменную, а сотни локальных.
СБИ
7
Вам следует добавить ссылку на пост в блоге Джоэла Спольски, где он предлагает свое объяснение того, почему использование типа переменной для получения венгерского уведомления является неправильным пониманием того, что это такое. У вас это хорошо, но некоторые люди могут искать что-то более авторитетное, и вы можете использовать это для поддержки своего дела. joelonsoftware.com/articles/Wrong.html
Шейн Веалти,
2
@Coder: К сожалению, typedefэто серьезно недооцененный инструмент
sbi
4
@Shane: я записал свое собственное мнение по этому вопросу. Если это случится с Джоэлом, то это нормально для меня, потому что я ценю его мнение, даже если я не согласен с некоторыми из них. Но я не вижу необходимости обращаться к другим «властям» с просьбой поддержать мое собственное мнение, если оно основано на более чем десятилетнем опыте с трудом завоеванным. Приятно, что вы разместили эту ссылку, однако всегда приятно видеть мнения других людей, с которыми можно сравнить.
СБИ
4
Давным-давно я был парнем из магазина CVS в магазине, и один из ведущих разработчиков изменил инициалы (операция по смене пола и т. Д., И его и ее имена не имели одинаковых инициалов). Всякий раз, когда она касалась файла (или подобного), она изменяла все его инициалы в новую форму. Я нахожу это чрезвычайно раздражающим, поскольку у нас будут все виды незначительных изменений в исторических особенностях, и было трудно понять, что на самом деле изменилось и почему. Изменение vecCityNamesк deqCityNamesв несколько сотен файлов , и вы делаете то же самое.
Дэвид Торнли
15

По какой-то причине существующие здесь ответы, кажется, танцуют вокруг обоснования венгерской нотации, не заявляя об этом прямо. Венгерская нотация полезна для добавления информации о типе (в теоретическом смысле типа ), когда это будет трудно сделать в самом языке . Как это бывает, обычно не так сложно использовать систему типов C ++ или Java таким образом, что венгерская нотация (как обычно описывается) совершенно излишня, и это, вероятно, привело к негативной реакции на нее - это добавляет работу программиста поддерживать эти аннотации во всех наших переменных naes, но обеспечивает дополнительное или почти полное отсутствие значения (и может даже нанести вред, так как код выглядит более загроможденным).

С другой стороны, если кто-то ограничивает использование венгерской нотации для ввода информации (опять же, в теоретическом смысле типа ), это неестественно инкапсулированный языком, тогда он может быть очень полезным. Например, C и C ++ передают ссылки на массивы как типы указателей, но ссылки на массивы и указатели имеют различные операции, которые должны выполняться над ними: массивы могут быть проиндексированы за пределами первого элемента, а указатели - нет. Это полезная информация, которая теряется в системе типов, как только массив передается функции в качестве аргумента. Таким образом, в нашей группе мы приняли аннотации имен переменных в коде C и C ++, чтобы определить, является ли переменная-указатель на самом деле указателем на отдельный элемент или указателем на массив. Принятие этого соглашения отчасти привело к значительному уменьшению возникновения проблем с повреждением памяти в нашей кодовой базе.

Эйдан Калли
источник
Венгерский сбой был вызван тем, что команда WinAPI неправильно использовала его для кодирования синтаксического типа переменной , а не ее семантического значения . (Подумайте dwпротив cb.) Не то, чтобы его оригинальная форма была бы менее полезной в ОО-языках: индекс по-прежнему является индексом, даже если он хранится в типе класса, а не во встроенном.
СБИ
1
+1 за указание на то, что реальный аргумент здесь о теории типов. Венгерская нотация - это метод дополнения системы типов дополнительной информацией, и поэтому ее следует сравнивать и противопоставлять другим методам дополнения системы типов (например, шаблоны, typedef и т. Д.), А не обсуждать ее эстетические достоинства (или его отсутствие).
Даниэль Приден
1
Речь идет конкретно о «Системах венгерских», бессмысленном дублировании заявленного типа, без лишней семантической информации. Может быть случай использования оригинальной концепции «венгерской нотации» семантических тегов для предоставления информации, выходящей за рамки, допустимые синтаксисом языка (в некоторых языках, включая C, но не C ++, где вы можете сделать это более надежно с пользовательскими типами) ), но дело не в этом.
Майк Сеймур
10

Это раздражает некоторых людей (понятия не имею, почему)

Причина, по которой меня это раздражает, заключается в том, что это небольшой скачок скорости для каждого идентификатора, который замедляет мое визуальное сканирование кода. СДЕЛАЙТЕ МАСЫ, КОТОРЫЕ ВЫ ПРАВИЛИ, ЧТО ДЕЛИТЕ, ЧИТАЙТЕ НА ИСПОЛЬЗОВАНИИ ТЕКСТА, КАК ЭТО.

dfan
источник
9

Ненависть - слишком сильное слово, ИМО. Вы можете написать свой код любым удобным вам способом; Я просто предпочитаю не использовать венгерскую нотацию в своем собственном коде, и если бы у меня был выбор, я бы предпочел не читать и не работать с этим в чужом коде.

Вы спросили, почему некоторые люди находят венгерские обозначения раздражающими. Я не могу говорить за других, но причины, которые меня раздражают:

  1. Это ужасно. Венгерский берет совершенно разумные имена и добавляет то, что составляет код. После того, как вы усвоили этот код, я уверен, что он имеет смысл, но для непосвященного это выглядит так, как будто кто-то запустил манипулятор имен C ++ в моем исходном коде.

  2. Это избыточно. Объявление переменной устанавливает ее тип; Я не чувствую необходимости повторять эту информацию в имени переменной. Это не так во всех языках: например, в Perl сигилы, такие как @ или $, добавленные к имени переменной, по существу определяют тип переменной, поэтому у вас нет другого выбора, кроме как использовать их.

  3. Это решает проблему, которой у меня нет. Методы и функции не должны быть такими длинными, чтобы вам приходилось искать декларацию локальной переменной или параметра, и они не должны включать в себя столько переменных, что вам будет трудно отслеживать, что к чему. Объявление локальных переменных близко к коду, который их использует, также помогает в этом отношении. Компиляторы C прошлого требовали, чтобы все локальные переменные были объявлены в начале функции, но это ограничение было снято давно.

  4. Это неполно Венгерская нотация была придумана для языка (BCPL), который не имел системы типов, а позже широко использовался в языке (C), который имел довольно ограниченное число нативных типов. IMO, он не очень хорошо работает с такими языками, как C ++ или Java, которые имеют расширенные системы типов. Почему я хотел бы использовать префикс для указания типа переменной, которая является нативным, например char [], но не является классом? С другой стороны, если я начну изобретать префиксы, такие как vecдля классов, я получу большую иерархию префиксов, параллельную моей иерархии классов. Если вам это нравится, вы можете это сделать; просто думать об этом вызывает у меня головную боль.

  5. Это неоднозначно , по крайней мере, насколько я понимаю. Какая разница между szFooа pszFoo? Первая - это строка с нулевым символом в конце, а вторая - указатель на строку с нулевым символом в конце. Но в C или C ++, насколько мне известно, любая строковая переменная фактически является указателем, поэтому они одинаковы или нет? Какой я должен использовать? Реальный ответ на самом деле не имеет значения - дело в том, что я не могу различить ответ, используя те самые обозначения, которые должны помочь мне избежать подобных вопросов. Объявление переменной, с другой стороны, должно быть однозначным, потому что это то, что использует компилятор.

Это то, что раздражает меня в венгерской нотации. Хотя даже как группа, я не думаю, что они полностью объясняют, почему венгерский язык был в значительной степени оставлен. Вот три основные причины, по которым большинство программистов не используют венгерский:

  1. Там нет веских причин, чтобы использовать его. Смотрите пункты 3 и 4 выше. Я мог бы, вероятно, жить с досадой, если бы венгерский предложил какое-то большое преимущество по сравнению с неиспользованием венгерского, но я не вижу его, и, очевидно, большинство других людей тоже не видят. Возможно, лучшее в венгерском языке было то, что это было широко используемое соглашение, и если вы придерживаетесь стандартного использования, вы можете разумно ожидать, что другие программисты с подобными навыками смогут понять нотацию.

  2. Увеличение влияния компаний, которые не являются Microsoft. Вероятно, было бы справедливо сказать, что большинство программистов, принявших венгерскую нотацию, сделали это, потому что именно так Microsoft пишет код, и его часто проще реализовать. Такие компании, как Google и Apple, имеют гораздо больше сфер влияния, чем в прошлом, и больше программистов, чем когда-либо прежде, перенимают стили тех компаний и других, которые в основном избегают венгерского. (Справедливо отметить, что вы все еще видите некоторые остатки, например, и Google, и Apple часто используют префикс «k» для постоянных имен.)

  3. Сама Microsoft отказалась от венгерского. Если вы ознакомитесь с разделом « Общие соглашения об именах», изложенным в его Руководстве по кодированию, вы обнаружите, что в нем выделено жирным шрифтом: не используйте венгерские обозначения.

Соответственно, одна из веских причин отказаться от использования венгерской нотации:

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

Калеб
источник
«Какая разница между szFooи pszFoo»? Один char*, другой char**занял у меня 0,25 секунды, чтобы понять разницу. Попробуйте побить это с Intellisense.
Кодер
2
@ Кодер, pnFooвероятно int*, не int**так, поэтому вы должны знать, что szтакже означает указатель. Я уверен, что это не большая проблема для ограниченного числа типов, которые установили венгерские префиксы, но в любом крупном проекте число типов определяется тысячами. Я не знаю об Intellisense, но IDE неуклонно улучшались в течение последних 25 лет, и я ожидаю, что эта тенденция сохранится.
Калеб
8

До сих пор я вижу следующие преимущества в его использовании:

  • Согласованное именование переменных

Если я назову все свои переменные после символов из Симпсонов, это тоже непротиворечиво, но выгодно ли это?

  • Вы видите тип без поиска (intellisense не работает / индексирует половину времени, поэтому это все еще веская причина)

Это единственная действительная причина, основанная на слабости одного конкретного инструмента ...

  • Семантика все еще может быть упакована во вторую часть имени

Это не выгода; вы просто заявляете об отсутствии ( массивного ) недостатка.

Майкл Боргвардт
источник
6

Среда IDE легко подскажет мне тип переменной, когда я наведу на нее курсор мыши. Так зачем копировать эту информацию? По сути, системная венгерская нотация является нарушением DRY со всеми подводными камнями, которые с ней связаны. Когда эта информация тривиально доступна в современной среде, нет смысла платить эту цену.

Последовательность не является преимуществом сама по себе. Не называть их с типом также соответствует. Вы могли бы иметь несогласованность, если бы только некоторые переменные имели свои типы в имени. И упаковывать семантику во вторую часть просто: «Ну, это не так уж и плохо», все остальные используют полное имя для семантики. У вас нет реальных преимуществ в списке.

DeadMG
источник
4
«Среда IDE легко подскажет мне тип переменной, когда я наведу на нее курсор». Да, в привет мире. В более крупных проектах я считаю эту функцию крайне ненадежной / медленной. Ctrl + Пробел, Ctrl + Пробел, Ctrl + Пробел, Ctrl + Пробел, Ctrl + Пробел, не идти ...
Кодер
3
Получите новую IDE. Или SSD, который творит чудеса. Или просто включите меньше ненужных заголовков.
DeadMG
1
Даже если IDE слишком медленная при отображении типа переменной или если она просто не в состоянии это сделать, методы / функции должны быть короткими, чтобы объявление переменной никогда не было слишком далеко от ее использования.
Кевин Панко
6

Еще один момент, связанный с традиционными формами венгерских обозначений, это то, что они обычно являются префиксами есть 2 проблемы imho здесь:

1) Человек-читатель, как правило, хотел бы сначала получить самую важную информацию, поскольку в большинстве венгерских языков закодированная информация, возможно, имеет меньшее значение, чем само название.

2) Префиксы влияют на лексическую сортировку, поэтому, если, например, вы собираетесь использовать префикс для обозначения интерфейсов или классов, а ваша IDE предоставляет отсортированный список из них, связанные классы / интерфейсы будут разделены в этом списке.

JK.
источник
2

Очевидно, что это сводится к мнениям, поэтому здесь будет сложно работать с фактами. Лично я нахожу, что аргумент для венгерской нотации несколько тонок в строго типизированных объектно-ориентированных языках. По моему опыту, ОО-приложения имеют тенденцию справляться со сложностью, сохраняя классность и краткость, и то же самое можно сказать и о функциях. Это означает, что при прочих равных условиях вы получите:

  • Больше классов / типов
  • Более короткие методы

Теперь, если вы хотите использовать венгерскую нотацию, вы должны решить, применять ли ее по всем направлениям, или просто использовать ее для определенных привилегированных типов и классов (например, классов базовой библиотеки). Последнее не имеет смысла для меня, а первое приводит к «лабиринту попыток найти разные сокращения для тысячи разных типов», на которые ссылался Петер Тёрёк. Это означает, что поддержание списков сокращений связано со значительными издержками, и обычно «согласованное именование переменных» выходит за пределы окна.

Второй пункт о более коротких методах означает, что в большинстве случаев вам не нужно проходить сотни строк кода, чтобы проверить, какой тип является переменной. Более осторожное присвоение имен переменным устранит некоторые другие ваши вопросы - например, cityNameпротив справедливости city. Я надеюсь, что cityNameэто не поплавок :)

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

Даниэль Б
источник
1

Я не знаю в контексте C ++, но в мире Java / C # я бы предпочел иметь осмысленные имена, которые передают либо язык домена, либо контекст, чем говорить мне, что strFirstNameэто String; должно быть очевидно, что это строка, или имя должно быть реорганизовано для лучшего понимания. Если вам требуется префикс для определения типа того, с чем вы работаете, я бы сказал, что ваше наименование является непоследовательным, недостаточно описательным или совершенно неверным. В современных языках я всегда предпочитаю более длинные имена, которые не оставляют двусмысленности, чем расплывчатые или двусмысленные имена.

Единственный раз, когда я использую венгерский язык, это для элементов управления ASP.NET, и это тем более, что IA) не нужно набирать что-то очень длинное, например « CustomerFirstNameTextBoxпротив» txtCustomerFirstName, и B) Так что Intellisense будет сортировать все типы элементов управления. Я чувствую себя "грязным", даже когда делаю это, но мне еще только предстоит найти лучший путь.

Уэйн Молина
источник
0

Мех - это на самом деле все о личных предпочтениях, независимо от того, как сильно человек пытается рационализировать свой выбор. Я лично придерживаюсь правила «Когда в Риме ...» и использую венгерский в коде, который часто вызывает Windows API. Для независимого от платформы кода я склонен следовать стилю стандартной библиотеки C ++.

Неманья Трифунович
источник
0

Ответ заключается в следующем вопросе: скажите, пожалуйста, как назвать следующие переменные:

char * nullTeridityString;
wchar * nullTeridityWideString;
строка stlString;
wstring stlWideString;
CString mfcString;
BSTR comString;
_bstr_t atlString;

Добавьте к этим константным строкам указатель на них и постоянные указатели на них.

неосторожный пешеход
источник
3
szFoo, wczFoo, strFoo, (w)strFoo, strFoo, bstrFoo,bstrFoo
Coder
0

Мне очень не нравится форма венгерской нотации, которую вы описываете. Причина? 90% времени не служит.

Например, немного (эквивалентного C ++. Фактически написанного на Delphi) кода из унаследованного проекта, который я вынужден терпеть:

pRecords[0]->FooMember=10;

... pRecord - это переменная типа TRecordList. TRecordList *pRecords[10];

Это класс, состоящий из orioerty с именем FooMember, который указывает на fFooMember ... или mFooMember в зависимости от того, является ли это "полем" или "членом" (подсказка: это одно и то же)

Проблемы? fFooMemberможет быть что-то вроде FooMember_, потому что мы всегда будем получать к нему доступ через публичное свойство FooMember. pRecords? Совершенно очевидно, что это указатель на тот факт, что вы разыменовываете его повсюду. TRecordList? Когда вы можете спутать имя типа и объект этого типа? Компилятор будет кричать на вас, а типы используются практически в тех местах, где находятся объекты (кроме статических свойств / методов)

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

Например, если бы у меня была форма для вашего имени.

Я хотел бы иметь класс с именем FirstNameForm. Внутри него lblFirstName и txtFirstName для метки и текстового поля соответственно. И публичное свойство FirstName для получения и установки имени в текстовом поле.

Это также может быть решено с помощью FirstNameLabel и FirstNameTextBox, но я считаю, что это будет долго печатать. Особенно с чем-то вроде GenderDropDownList и тому подобное.

Таким образом, в основном венгерская запись в лучшем случае раздражает на систематическом уровне, а в худшем случае вредна (как и другие ответы о проблемах с рефакторингом и согласованностью).

Earlz
источник