Как стать автором
Обновить

Комментарии 90

где вы видите имена, такие как lpsz_name

Я пойму, что это «Long Pointer to String with a Zero terminator», но еще это и отхождение от гайдлайна. По гайдлайну должно быть lpszName. Знак подчеркивания есть только у "m(ember)" и "g(lobal)".
Пруф


Это всё что нам надо знать о проблеме написания и чтении гайдлайнов. :)

Еще несколько раз видел a(rgument) для аргументов.

lpsz_name — корректный вариант при использовнии гайдлайна по префиксам при именовании переменных с_разделением_слов_подчеркиванием. Общий гайдлайн Microsoft включает в себя рекомендации не только по префиксам, но и по именованию (camelCase). Но нет никакой проблемы, что в проекте гайдлайн используется не целиком, а частично.
А в данном случае это, скорее всего, просто мелкая невнимательность автора, который привел не совсем удачный пример.

Ооо, теперь я знаю имя того, кто притащил эту хрень в Java на Андроид!
Лично я HN в Java не переношу. Чтобы найти переменную с такой нотацией, надо сначала вспомнить ее тип, угадать какие еще дикие бредни пришли в голову разработчику, когда он решил поставить lpsz или еще что-то, и только потом можно поискать по имени. Вместо того чтобы набрать "." и начать вводить очевидное имя, приходится угадать m, g, lpsz, wtf и пр., и только потом искать по имени.
Конечно, всегда можно заглянуть в начало класса и посмотреть там, но тогда вообще нет разницы, есть мета или нет.
А при правильно составленном Coding Conventions, можно избежать вообще необходимости угадывать какие есть поля в классе, обращаясь к нему снаружи, т.к. можно просто прописать работать только через геттеры и сеттеры.
Спасибо, прочитал. :) Я не пишу на С и С++, поэтому стал сталкиваться с такой нотацией уже в более высокоуровневых языках. Не знаю как было в 70-х и 80-х, но тащить это в Java и C# сейчас… мягко говоря, странное решение.
Не в защиту префиксов (сам их не люблю), но справедливости ради.
В современных средах после точки можно вводить любой кусок имени идентификатора, сопоставление ищется по подстроке (VisualAssist, например, такое умеет).
P.S. пардон, ниже уже об этом написали.
Вместо того чтобы набрать "." и начать вводить очевидное имя, приходится угадать m, g, lpsz, wtf и пр., и только потом искать по имени.
Что интересно, если использовать нижнее подчёркивание в именовании, то этого можно почти избежать:

image
Автодополнение и без этих префиксов будет точно так же работать.

Вы смешали в кучу префиксы по типу и по видимости, от чего автор как раз предостерегает. Если у вас только 'm', то прекрасно понятно, писать его или нет, ведь вы точно знаете, какую переменную ищете — локальную или член класса.


Coding Conventions не помогут вам в коде метода класса понять, например, использует/изменяет ли данный кусок кода состояние класса (т.е. переменные-члены) и можно ли его отрефакторить,

Если я ищу член класса, то я так и пишу: this.

Использование средств разработки с не тривиальным поиском после «набрать .» решило бы эту проблему.
Мне сразу стало ясно, что поля действительно являются наиболее важным аспектом переменной, поэтому я решил, что нам не нужны дальнейшие соглашения, чтобы отличать локальные переменные от параметров функции.
Как жаль, что этот персонаж не видел IDEA, в которой поля обычно выводятся в коде жирным темно-фиолетовым цветом. Из-за тех, кто привык набирать текст в говноредакторе через замочную скважину теперь страдают многие.

И его это «объяснение»:
Код часто читается вне IDE (начиная, по иронии судьбы, со скриншота, снятого с обсуждения на reddit, у которого нет подсветки). Я читаю код в браузерах, терминалах, diff utils, git tools и т. д. Большинство из них не имеют подсветки, которая бы упростила анализ кода, поэтому использование метаданных идентификатора может помочь в таких случаях.
Совершенно не причина поганить весь свой код. Дифы, мерджи и другие гитовые операции отлично работают и отображаются с подсветкой в IDEA.

И?

DEA

Вы конечно всё хорошо и правильно написали. Но это справедливо только для тех, кто пользуется IDEA. Но что же делать всем остальным?
И немного отвечая на комментарий habradante: в IDEA, если я не ошибаюсь, если писать a.Name, он будет подсказывать и .lpszName в том числе (если не в первую очередь)

Будет, но не в первую очередь, если есть более удачные совпадения. Можно также писать a.name и получить подсказку для a.mName или a.CNa и получить a.mComplexName. Нормальный человеческий fuzzy search.

Я Netbeans пользуюсь, он не такой умный. Но искать по коду приходится не только в IDE. Так вот искать/грепать по .name проще и понятнее, чем вспоминать префикс.
Грепать лучше по чему-то уникальному. Просто «name» явно таким не является.
Но что же делать всем остальным?
Что может помешать использовать наилучшую Java (да ещё и официальную для Андроида) IDE? Плюс, ещё и бесплатную (Community Version отлично работает с Андроидом).
Те, кто не пользуется IDEA, пользуются Eclipse и немного NetBeans, там тоже есть подсветка полей и переменных.

Автор оригинальной статьи, вероятно, как и положено сеньору в Гугеле, проводит больше времени в Gerrit, чем в IDE. А там как раз будет дифф без подсветки и прочего. А тащить ветку локально чтобы посмотреть на нее через IDE это слишком много телодвижений для уважаемого человека.


Слуга ваш покорный пострадал на прошлой работе в попытках аргументированно объяснить, что код пишет 50 человек и каждый день, а ревью делают 4 и только перед финалом. И исходя из этого раскладывать компонент по 6 местам и фигачить полукилометровые имена с префиксами несколько иррационально. Тем более что за 12 месяцев ни каких замечаний от оных уважаемых людей, кроме соответствия гайдлайнам, я не видел. На что получил вполне ожидаемый ответ — мы есмь четыре всадника апокалипсиса, покайсо холоп и убойся гнева нашего. На том и разошлись. ;-)

код пишет 50 человек и каждый день, а ревью делают 4

А почему всего 4? Всего четыре подсистемы с 4 владельцами?
Просто у нас перекрестное ревью, и т.к. в команде все "сеньоры",
то аппроксимируя на ваши цифры 50 пишут и 50 проводят ревью


и только перед финалом

перед каким финалом, типа неделю разрабатываешь в отдельной ветке, а
потом на review отправляешь?


фигачить полукилометровые имена с префиксами

полукилометровые из-за одной буквы m вначале?

У нас тоже перекрёстные ревью, в основном народ смотрит дифф без подсветки. И большинство проголосовало за избавление от префикса m. Что мы делаем не так?

а почему всего четыре

потому что так у них повелось. См про качество этого процесса в том же параграфе.


перед каким финалом

pull request / git workflow. Ревью делаются на PR.


полукилометровые из-за одной буквы m

нет, из-за naming conventions у компонентов и методов. Типа PublicCampaignAnalyticsEventTransitiveViewFactory::analyticsEventCreationTimestamp. Это в общем из той же оперы.

… а код эти 50 человек пишут одноразовый, поэтому не может возникнуть необходимости разбираться в нем через год (тем более другому разработчику0...

Одно с другим слабо связано, как отмечено выше. Если на ревью проверяется главным образом стиль кодирования и NPE, на качество кода оно слабо влияет.

Если программист, читая код метода, не может вспомнить употребил ли он здесь поле, параметр или локальную переменную, значит он что-то сделал не так. Например, написал слишком длинный и/или сложный метод. Такие иногда встречаются, но именно иногда и это повод провести рефакторинг или снабдить код комментариями. Но точно не повод поганить весь этот и остальной код бесполезным префиксом m. Он бы ещё доллар из похапе догадался притащить...

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

И что, вот впервые видит и сразу начинает читать код прямо с середины метода не интересуясь ни сигнатурой метода, ни тем, что там было в начале? Позвольте поинтересоваться, а с какой неведомой целью этот ваш "программист" занимается настолько бестолковой деятельностью? От бессонницы спасается? Тогда ему абсолютно всё-равно какие там переменные параметры, а какие — поля.

Исправление нпе в легаси по логу от клиента. Открыл, нашел строку, исправил и забыл.
Где тонко — там и рвётся

Всегда стараюсь тушить на корню такие фиксы: обязательно нужно разбираться во всей системе, познать предпосылки и причину аварийного состояния.
Добавить проверку на нул, это не исправить, это отодвинуть ошибку в другое место. Авось, в другом месте и не упадёт, не космолёт же пишем?
Вам не заплатят за анализ миллиона строк легаси кода из-за ошибки допущенной 5 лет назад, но впервые проявишейся.
И в 99% случаев нпе это просто нпе.

Профессионал всегда делает работу хорошо и до конца, не зависимо от бюджета. Или в другой формулировке: если ты не можешь сделать работу хорошо за небольшие деньги, ты и за большие не сможешь.
Как код становится 5-ти летним легаси? Да вот так, когда его затыкают проверками на npe, хотя потратив больше времени, можно слегка отрефакторить задев более высокий слой. И, быть может, проверка не понадобится, такая ситуация уйдёт сама собой.
NPE это симптом, а не болезнь.

НПЕ это просто ошибка.
Код становится 5-ти летним легаси через 5 лет. Ставить костыли или вообще как-то шевелиться для этого не нужно.
Про сияющие доспехи профессионалов проигнорирую.
Код становится 5-ти летним легаси через 5 лет.
Код становится 5-ти летним легаси после 5 лет втыкания костылей. Глядя на код в нашем проекте 3х летней давности (иногда нужно править ошибки в старых ветках) мне плакать иногда хочется, а с современным его состоянием — нет. Это, собственно, и отличает профессионала от непрофессионала. «Сиять» для этого не нужно, нужно работать.

NPE это не просто ошибка. В том плане, что скорее всего настоящая ошибка находится совсем не в той строке, которую вы в логах увидели, а где-то выше по стеку. И это, скорее всего, логическая ошибка.

А зачем вам для этого знать был null присвоен полю или локальной переменной?

Зачем венгерская нотация в статически типизированных языках???
Для того, чтобы указать в ней то, что не указано в типе?

Никогда не понимал использование lpsz (а особенно wParam для 64-битного значения). Но возможность отличать mLength от length — не кажется мне бесполезным. Типы-то у них совпадают… а подсветка, всё-таки, не является частью языка.

Другое дело, что подчёркивание в конце мне нравится больше — хотя это уже совсем по HN…

Учитывая, что те же строки бывают и C-string, и BStr, и ANSI, и Unicode, и const, и out. И ещё черта лысого, а C++ легко кастит все эти типы туда-сюда, от такой нотации много пользы.

Если «C++ легко кастит все эти типы туда-сюда» и при этом программа работает — то какая вам разница что конкртно там используется? А если не работает — то кто придумал такой API?

C++ — он, как бы, в отличие от C не умеет «из коробки» преобразовывать друг в друга никак не связанные между собой типы. Его этому нужно учить. И желательно — так, чтобы работало.
Есть разница. Например, передать const (w)char * вместо BSTR это UB, пусть даже и скомпилируется. Кто придумал такой api? Майкрософт, который использовал венгерку
Но возможность отличать mLength от length — не кажется мне бесполезным.

Мне для этих целей больше this использовать понравилось. Правда C++ использую. Использование полей с this может и длиннее, но без него я знатно путался.
В Python, где другого способа нет — это работает, в C++/Java — нет. Потому что пропущенный this-> не приводит к ошибке компиляции и в рантайме тоже «стреляет» не сразу. Хотя выглядит красиво, бесспорно.

пропущенный m, как не странно, тоже не приводит к ошибке компиляции

Только в тех случаях, когда у вас есть аналогичная переменная без «m». Такого лучше в функциях длиннее трёх строк (читай: конструкторы) просто не допускать. А this-> пропущенный компилируется всегда — и потому отсутствию this-> доверять нельзя никогда, что и делает его бессмысленным.

В javascript также — все поля и методы только через this
Когда только начинал учить после других языков — страшно бесило


Но сейчас (я стал фронтенд-ом) мне это очень нравится.

Похоже вы не понимаете что такое венгерская нотация. Почитайте статью подробнее и вопрос отпадёт.
Венгерская нотация явно имела повод для существования во времена программирования в блокнотах. Зачем префикс m или m_ к имени сейчас, если IDE выделяет поля класса цветом? Пользуюсь лидирующим _ для полей в с++ только лишь для того, чтобы писать нормальные имена для геттеров: скажем, поле _initialized, геттер initialized()

Префиксы типа, аля lpwzPath, конечно, нагляднее, чем переходить к месту определения переменной в IDE, но существенно увеличивают объем кода. В итоге его становится сложнее читать попросту потому, что его много.

Вот семантическая часть полезна в программировании GUI. Это банально самый лаконичный способ именовать группы виджетов с одним общим назначением
Зачем префикс m или m_ к имени сейчас, если IDE выделяет поля класса цветом?

Чтобы автокомплит отфильтровал поля класса среди методов, статических полей и прочего.
название метода/класса и сотни других вещей тоже может начинаться с m. Зато названия публичных методов/классов не могут начинаться с _
Тем и странен выбор «m» вместо «m_».

То есть вы жмёте m и дальше в списке ищете нужное имя? Или всё же пишите 2-4 первые буквы?

Если человек, придерживающийся этой нотации, хочет увидеть в автокомплите список членов типа, то он жмет «m_».
Префиксы типа mObject в андроиде — зло. Нет, если пишешь код в блокноте, может и полезно, но абсолютное большинство разработчиков пользуется нормальными IDE, в которых эти префиксы только мешают, кроме того, приходится рефакторить скопипащенный код для «обычной» джавы, чтобы не перемешивать стили.
Префиксы/постфиксы типа tvName — штука полезная из-за того, что может быть, грубо говоря, TextView для имени, и может быть CheckBox для имени: они удобны, чтобы не выдумывать новые имена для объектов.

Итого: я пользуюсь постфиксами для объектов типа View (nameTv, nameEt, nameBtn и т.д.), а префиксами для полей перестал пользоваться где-то через полтора года после начала разработки под Android, когда понял, что они бесполезны.
Не встречал ни одного проекта, где мне бы захотелось использовать венгерскую нотацию.
Один из многих холиваров на тему стиля, только и всего.

Я понимаю, что статья про другое, но… Неужели человек, разрабатывающий гайдлайн для разработчиков не догадался увести if (Log.Debug) внутрь функции Log.d? И никаких однострочников и холиваров про скобки…

Андроид Апи в принципе не очень грамотные программисты пилили. Все эти жизненные циклы и отдельные способы работы с разными визуальным компонентами могли прийти в голову только бестолковому новичку.

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

Разница в том что в случае с if внутри аргументы Log.d будут вычисляться даже если логи выключены.

if намного быстрей, чем вызов функции.

В случае openjdk/oracle jdk зачастую if вне функции и внутри одинаковы по времени после JITа. Существенное отличие — сбор строки для логгирования (вычисление аргументов). В том же slf4j пошли путём использования интерполяции уже внутри вызова логгера.

С первой же миллисекунды быстрее? Извините, но… Не верю. JITу нужно долго «прогреваться», «разгоняться» — и в новых версиях Java этот процесс не становится более быстрым.

А процессы в Андроиде должны умирать и рождаться незаметно для пользователя и «свежезапущенный» процесс должен работать так же, как «прогретый». Зачем такую систему вообще сотворить на Java — отдельный вопрос, но раз уж сотворили, то закладываться на JIT не стоит…
С первой же миллисекунды быстрее? Извините, но… Не верю. JITу нужно долго «прогреваться», «разгоняться» — и в новых версиях Java этот процесс не становится более быстрым.

Естественно не сразу. Но логгер дёргают достаточно часто, и его методы должны прогреться довольно быстро.


А процессы в Андроиде должны умирать и рождаться незаметно для пользователя и «свежезапущенный» процесс должен работать так же, как «прогретый». Зачем такую систему вообще сотворить на Java — отдельный вопрос, но раз уж сотворили, то закладываться на JIT не стоит…

Они с ART сейчас вообще пошли в сторону AOT-компиляции. Но вообще решения по тому что лучше стоит принимать не исходя из того, что "на JIT закладываться не стоит", а исходя из результатов профилирования.


Я не занимаюсь разработкой под android, но в случае openjdk на сервере по моему опыту логгирование жрёт довольно незначительное количество ресурсов.

Но логгер дёргают достаточно часто, и его методы должны прогреться довольно быстро.
Чтобы достичь скорости, которую даёт описанный в статье if «прогреть» нужно не логгер, а, фактически, всю программу — чтобы метод за'inline'ился и потом исчез…

Но вообще решения по тому что лучше стоит принимать не исходя из того, что «на JIT закладываться не стоит», а исходя из результатов профилирования.
Это смотря чего вы хотите добиться. Подход, описанный в статье, не только ускоряет код, но и уменьшает его. А по моему опыту тут — профилирование не работает. В типичной программе есть, как правило, участки, на выполнение которых уходит 90% времени, но нет участков, которые занимают 90% объёма.
Чтобы достичь скорости, которую даёт описанный в статье if «прогреть» нужно не логгер, а, фактически, всю программу — чтобы метод за'inline'ился и потом исчез…

Даже компиляция всего метода с выделенным hot path, который делает просто ret для trace/debug уже даёт очень неплохой результат. Останется нелокальный переход, но это не столь страшно. Кроме того, настройка логгирования (включение, например, debug для определенного package'а) может меняться во время жизни приложения, что вызовет deopt и компиляцию когда-нибудь в будущем. Мне сейчас, честно говоря, несколько лень брать в руки JMH чтобы сравнить эти два варианта.


Это смотря чего вы хотите добиться. Подход, описанный в статье, не только ускоряет код, но и уменьшает его. А по моему опыту тут — профилирование не работает. В типичной программе есть, как правило, участки, на выполнение которых уходит 90% времени, но нет участков, которые занимают 90% объёма.

Не сказал бы, что уменьшает:


if (Log.DEBUG) Log.d(tag, "someVar=" + someVar + ", anotherVar=" + anotherVar);
// versus
log.debug(tag, "someVar={}, anotherVar={}", someVar, anotherVar);
я не особо разбираюсь в дебрях JIT и прочих возможностей оптимизации java-кода, но даже если это все вдруг не сработает, потери на сопровождение такого кода по всей кодовой базе приложения имхо дороже, чем потеря производительности нескольких мили-(микро?)секунд на вызове функции.

Кажется, это про оптимизацию. Не уверен, что компилятор выкинет вызов метода, даже если он пустой. А if(false) выкинет.

При всем уважении к сишникам, по моим наблюдениям, люди которые переходят с с/с++ на другие языки, еще очень долго потом тянут с собой сишные погремушки. И переучить их очень тяжело. Люди, оставайтесь на си.
То же самое можно сказать про Java, Haskell и вообще любой язык программирования. Людям свойственно хотеть использовать то, что они уже знают.

На C++ код, написанный человеком с 10 годами работы на Java тоже без слёз не взглянешь. Тормоза получаются знатные.
тормоза — полбеды. Сотни new без единого delete там, где объект мог бы вообще лежать на стеке — вот по чему рефакторинг плачет
Да, при переходе с си на язык вроде java и обратно, нужно мозг менять практически целиком. У них слишком много противоположных подходов в ключевых местах.
Так и не понял зачем было вообще изобретать свой code style, когда есть готовый общепринятый java code style?

Это который из?

По большому счету, почти любой существующий был бы лучше, чем новый.

Как пример lpwzPath прекрасен, но это все прекрасно работает, если есть готовый LLD и нет никаких отклонений.


Приведу пример:


uint16_t mu16_InstanceId;

Предположим, у вас есть 50 строк кода где вы используете этот член класса, и на каком-то этапе вы понимаете, что 16 бит уже не катит и вы меняете тип, имя переменной и еще 50 строк кода, где она была использована (хотя семантический смысл там не поменялся).


После такого diff будет выглядеть довольно раздуто.

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

Странно. Я вообще начинал с венгерки. Думал что она прекрасна, позволяет избежать ошибок и т.д. Потом пересел на Java, поработал в нормальных IDE, и для меня необходимость в венгерке отпала. А после того, как пописал на языках, где есть функционал val (или auto), то есть тип слева от переменной можно не указывать, почему то пришло понимание, что это тоже очень хорошо. Пришло понимание, что нужно думать об имени переменной, а не о типе, о типе должен компилятор, а не я, постоянно помнить. В результате гораздо стало проще рефакторить а также гораздо проще читать код. Ошибаться стал меньше, чем когда венгерку использовал.


Учитывая, что сейчас я в имени никакую информацию о типах стараюсь не давать, а то и вообще типы явно не указываю, то следует ли считать, что лет 15 назад я был лучшим разработчиком, чем сейчас :)? Я ведь тогда многое что делал дополнительно, еще и когда скобочку закрывал, я в комментах писал к чему эта скобочка относится и тому подобное. А сейчас забил на это, и просто делаю методы короткими, а имена максимально понятными.

Это опыт. Большинство с опытом пишут более простой и лаконичный код на «автомате».
Все эти lpsz рождались когда не было никакой подсветки синтаксиса и такая нотация была вполне оправдана. Позже контекстная подсветка появилась в Visual Assist для Visual Studio. Позже был Resharper с опцией «highlight usage». А еще позже появился Android. Насколько помню даже тогда Eclipse имел подсветку синтаксиса и наверняка умел отличить локальную переменную от поля класса. Ну если не имел, то NetBeans и Intellij Idea уж точно имели, так что не было никакой необходимости тащить этот костыть в Android.
Всё проще: если чего-то не умеет Gerrit, то неважно чего там умеет NetBeans, IntelliJ Idea или Eclipse. Gerrit подсветку синтаксиса умеет, но отличать локальные переменные от полей класса — нет. Всё. Вопрос закрыт. Для разработчиков Android, разумеется.

Ваш workflow может отличаться и вам, возможно, этот префис-суффикс и не нужен…
НЛО прилетело и опубликовало эту надпись здесь
За четверть века что пишу, так душа и не приняла венгерскую нотацию. Не припомню чтобы она прибавила продуктивности хоть в одном проекте.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Изменить настройки темы

Истории