private String mName;
Это из-за меня.
Я так и сказал — это моя вина.
Эта тема всплывает снова и снова, обсуждение на reddit напомнило, что я никогда не объяснял откуда взялась эта нотация, а также, насколько она неправильно понимается людьми. Поэтому мне бы хотелось воспользоваться возможностью, дабы прояснить некоторые вещи, и я сделаю это в двух частях:
- Как появилась m-нотация.
- Почему вы, вероятно, не понимаете, что такое венгерская нотация.
M-нотация
Я был одним из первых инженеров, работающих над Android, и мне было поручено разработать руководство по стилю для Android API (для нас, команды Android) и пользовательского кода. В то время у нас было мало Java разработчиков и мало кода на Java, поэтому разработать руководство до того, как кода будет огромное количество — было очень важным.
Когда дело доходит до определения полей, я становлюсь немного предвзят. В то время я уже написал приличное количество Java, Windows и кода на C ++, и я обнаружил, что использование определенного синтаксиса для полей бывает очень полезным. Microsoft использует m_ для этого, в то время как обычно используется лидирующий символ подчеркивания (например, _name) в C ++. С тех пор, как я начал писать Java-код, меня всегда беспокоил тот факт, что Java отошел от этого соглашения.
Но моя задача состояла в том, чтобы написать руководство по стилю для Java, выполнив, таким образом, одну из наших целей с первого дня работы над Android — создать платформу разработки, где программисты Java будут чувствовать себя очень комфортно.
Поэтому я отложил в сторону свои предубеждения и потратил некоторое время на изучение внутренних руководств по стилю Sun и Google, и я придумал собственное руководство для Android, которое состояло на 99% из того, что предлагалось этими двумя руководствами, но с несколькими очень маленькими изменениями.
Одно из отличий, которое я помню, была связана с фигурными скобками. Хотя для обоих руководств по стилю требуется использовать фигурные скобки для всего, я ввел исключение, когда продолжающий оператор может поместиться в одной строке. Идея этого исключения заключалась в том, чтобы учесть распространенную идиому логирования в Android:
if (Log.DEBUG) Log.d(tag, "Logging");
Без этого исключения логирование занимало бы много пространства экрана, что, и с этим согласились все, нежелательно.
Итак, это была первая версия нашего руководства по стилю, и оно не содержало никаких требований к префиксам у полей.
Я отправил гайд команде, и, к моему удивлению, он никому не понравился, именно потому, что он не предусматривал синтаксиса полей. Все считали, что поля должны быть стандартизированы, и они не согласятся с руководством, у которого нет такого правила.
Поэтому я вернулся к своей доске для рисования и обдумал несколько вариантов стандартизации.
Я принял во внимание _name и m_name, как упоминалось выше, но отклонил их, потому что подчеркивание было слишком большим отклонением от стандарта Java. Я столкнулся с несколькими другими, более экзотическими нотациями (например, с использованием префикса «iv» для «instance variable»), но в конечном счете я отклонил их всех. Независимо от того, что я рассматривал, префикс «m» крутился у меня в голове как самый разумный и наименее объемный.
Итак, что было очевидным решением? Берете «m», убираете подчеркивание и используете camelcase. Таким образом родилось mName.
Это предложение было принято командой, и тогда мы сделали это официальным обозначением.
Вероятно, вы не понимаете венгерскую нотацию
Всякий раз, когда возникает дискуссия о венгерской нотации (HN), я замечаю, что большинство людей, похоже, думают, что каждый раз, когда вы добавляете некоторые метаданные в идентификатор, это автоматически HN. Но это игнорирует основную концепцию HN и очень продуманный дизайн, который Simonyi вложил в нее, когда он придумал это обозначение.
Прежде всего, существует множество различных метаданных, которые вы можете добавить к именам идентификаторов, и все они принадлежат к разным категориям. Вот категории, которые я определил на данный момент (их может быть больше):
- Информация о типе.
- Информация о видимости.
- Семантическая информация.
Давайте рассмотрим их по очереди.
Информация о типе
Это, пожалуй, наиболее распространенное использование метаданных поля: наименование поля таким образом, чтобы его тип можно было узнать по имени. Это используется повсюду в коде Win32 / 64, где вы видите имена, такие как lpsz_name, для обозначения «Long Pointer to String with a Zero terminator». Хотя эта нотация кажется чрезвычайно многословной и сложно читаемой, фактически у Windows программистов она интерпретируется в голове практически мгновенно, и добавленная информация действительно очень полезна для отладки многих непонятных ошибок, которые могут произойти в недрах системы Windows, в основном из-за очень динамичного характера многих его API и большой зависимости от C и C ++.
Информация о видимости
Это то, что используется в Android: использование метаданных для указания с каким типом переменной вы имеете дело: поля, локального или функционального параметра. Мне сразу стало ясно, что поля действительно являются наиболее важным аспектом переменной, поэтому я решил, что нам не нужны дальнейшие соглашения, чтобы отличать локальные переменные от параметров функции. Еще раз: обратите внимание, что эти метаданные не имеют ничего общего с типом переменной.
Семантическая информация
Это, на самом деле, наименее используемая информация в метаданных и, тем не менее, возможно, самая полезная. Такая дифференциация может применяться к переменным идентичных или похожих типов, или к идентичным или сходным областям, но принадлежащим к разной семантике.
Это соглашение можно использовать, когда вам нужно различать переменные подобных типов, но используемые в разных целях. В большинстве случаев разумное имя приведет вас к цели, но иногда метаданные — единственный выход из ситуации. Например, если вы разрабатываете графический интерфейс, который позволяет пользователю вводить имя, то вы можете иметь несколько вариантов view, называемых «name»: edit text («textName»), text view («tvName»), кнопки для подтверждения или отмены («okName», «cancelName», и так далее...).
В таких примерах важно четко указать, что все эти идентификаторы относятся к одной и той же операции (редактирование имени) при дифференциации их функции (метаданных).
Надеюсь, теперь у вас должно быть более точное представление о венгерской нотации, и я настоятельно рекомендую прочитать статью Джоэла Спольси «Making wrong code look wrong» на эту тему, которая должна помочь понять все эти пункты.
Итак, что вы думаете о венгерской нотации?
Прежде всего, я думаю, что нам нужно прекратить использовать термин «Венгерская нотация», потому что он слишком расплывчат. Когда я задаю этот вопрос, я обычно прошу людей уточнить, о каком из трех, перечисленных выше вариантов, они говорят (и в большинстве случаев они не уверены и им нужно время подумать об этом).
Я просто использую термин «метаданные идентификатора», чтобы описать общую идею добавления информации к простому имени идентификатора. И, в целом, я думаю, что этот подход может иметь достоинства в каждом из перечисленных случаев. Я не думаю, что это должно использоваться всегда и везде по умолчанию, но это определенно полезно, особенно в примере графического интерфейса, который я описал выше. Я встречаю такие примеры на регулярной основе и не использование метаданных идентификатора для такого типа кода, приводит к тому, что код сложнее читать (как для автора, так и для будущих читателей) и поддерживать.
Я также не согласен с аргументом: «Сегодня наши IDE могут различать все эти идентификаторы цветами, чтобы нам больше не нужно было делать этого самим». Этот аргумент ошибочен по двум причинам:
- Код часто читается вне IDE (начиная, по иронии судьбы, со скриншота, снятого с обсуждения на reddit, у которого нет подсветки). Я читаю код в браузерах, терминалах, diff utils, git tools и т. д. Большинство из них не имеют подсветки, которая бы упростила анализ кода, поэтому использование метаданных идентификатора может помочь в таких случаях.
- Подсветка в IDE по-прежнему не поможет вам разобраться в неоднозначных случаях, таких как, например, графический интерфейс, описанный выше. Есть еще случаи, когда вы, разработчик, знаете больше о своем коде, чем может знать IDE, и добавление метаданных идентификатора — это единственный разумный выбор, который вы можете сделать.
Не слушайте людей, которые говорят вам, что метаданные идентификатора никогда не должны использоваться или что их следует использовать всегда. Такой вид именования — это всего лишь инструмент в вашем ремесле разработчика, и здравый смысл должен относительно легко для вас определить, когда настало время добавить некоторые метаданные к вашим идентификаторам.
Наконец, я часто вижу бурные реакции по поводу этой проблемы. В течение 30 лет, что я писал код, я заметил, что после нескольких дней написания кода по новому руководству по стилю вы просто перестаете его замечать и полностью следуете ему. Были времена, когда я не мог терпеть код, который не писался с отступами с двумя пробелами, а через несколько месяцев после работы над проектом с четырьмя пробелами я почувствовал обратное. То же самое происходит с соглашениями об именах. Вы привыкнете к чему угодно, если соглашения применяются по всей базе кода, над которой вы работаете.
Комментарии (88)
habradante
18.07.2017 16:28+28Ооо, теперь я знаю имя того, кто притащил эту хрень в Java на Андроид!
Лично я HN в Java не переношу. Чтобы найти переменную с такой нотацией, надо сначала вспомнить ее тип, угадать какие еще дикие бредни пришли в голову разработчику, когда он решил поставить lpsz или еще что-то, и только потом можно поискать по имени. Вместо того чтобы набрать "." и начать вводить очевидное имя, приходится угадать m, g, lpsz, wtf и пр., и только потом искать по имени.
Конечно, всегда можно заглянуть в начало класса и посмотреть там, но тогда вообще нет разницы, есть мета или нет.
А при правильно составленном Coding Conventions, можно избежать вообще необходимости угадывать какие есть поля в классе, обращаясь к нему снаружи, т.к. можно просто прописать работать только через геттеры и сеттеры.da-nie
18.07.2017 19:41А вы не читали статью Борескова про эту нотацию? :) Он тоже не любит её.
habradante
18.07.2017 20:41+2Спасибо, прочитал. :) Я не пишу на С и С++, поэтому стал сталкиваться с такой нотацией уже в более высокоуровневых языках. Не знаю как было в 70-х и 80-х, но тащить это в Java и C# сейчас… мягко говоря, странное решение.
to_climb
18.07.2017 20:07+6Не в защиту префиксов (сам их не люблю), но справедливости ради.
В современных средах после точки можно вводить любой кусок имени идентификатора, сопоставление ищется по подстроке (VisualAssist, например, такое умеет).
P.S. пардон, ниже уже об этом написали.
Donutellko
18.07.2017 23:19+1Вместо того чтобы набрать "." и начать вводить очевидное имя, приходится угадать m, g, lpsz, wtf и пр., и только потом искать по имени.
Что интересно, если использовать нижнее подчёркивание в именовании, то этого можно почти избежать:
Steed
19.07.2017 14:20Вы смешали в кучу префиксы по типу и по видимости, от чего автор как раз предостерегает. Если у вас только 'm', то прекрасно понятно, писать его или нет, ведь вы точно знаете, какую переменную ищете — локальную или член класса.
Coding Conventions не помогут вам в коде метода класса понять, например, использует/изменяет ли данный кусок кода состояние класса (т.е. переменные-члены) и можно ли его отрефакторить,
Jamdaze
19.07.2017 15:15Использование средств разработки с не тривиальным поиском после «набрать .» решило бы эту проблему.
Revertis
18.07.2017 17:35+6Мне сразу стало ясно, что поля действительно являются наиболее важным аспектом переменной, поэтому я решил, что нам не нужны дальнейшие соглашения, чтобы отличать локальные переменные от параметров функции.
Как жаль, что этот персонаж не видел IDEA, в которой поля обычно выводятся в коде жирным темно-фиолетовым цветом. Из-за тех, кто привык набирать текст в говноредакторе через замочную скважину теперь страдают многие.
И его это «объяснение»:
Код часто читается вне IDE (начиная, по иронии судьбы, со скриншота, снятого с обсуждения на reddit, у которого нет подсветки). Я читаю код в браузерах, терминалах, diff utils, git tools и т. д. Большинство из них не имеют подсветки, которая бы упростила анализ кода, поэтому использование метаданных идентификатора может помочь в таких случаях.
Совершенно не причина поганить весь свой код. Дифы, мерджи и другие гитовые операции отлично работают и отображаются с подсветкой в IDEA.aliksend
18.07.2017 17:50+2Вы конечно всё хорошо и правильно написали. Но это справедливо только для тех, кто пользуется IDEA. Но что же делать всем остальным?
И немного отвечая на комментарий habradante: в IDEA, если я не ошибаюсь, если писатьa.Name
, он будет подсказывать и.lpszName
в том числе (если не в первую очередь)grossws
18.07.2017 17:56+1Будет, но не в первую очередь, если есть более удачные совпадения. Можно также писать
a.name
и получить подсказку дляa.mName
илиa.CNa
и получитьa.mComplexName
. Нормальный человеческий fuzzy search.
habradante
18.07.2017 18:08+2Я Netbeans пользуюсь, он не такой умный. Но искать по коду приходится не только в IDE. Так вот искать/грепать по .name проще и понятнее, чем вспоминать префикс.
netch80
19.07.2017 07:28-1Грепать лучше по чему-то уникальному. Просто «name» явно таким не является.
Revertis
18.07.2017 18:37-1Но что же делать всем остальным?
Что может помешать использовать наилучшую Java (да ещё и официальную для Андроида) IDE? Плюс, ещё и бесплатную (Community Version отлично работает с Андроидом).
Flammar
18.07.2017 19:07Те, кто не пользуется IDEA, пользуются Eclipse и немного NetBeans, там тоже есть подсветка полей и переменных.
borv
18.07.2017 21:22+7Автор оригинальной статьи, вероятно, как и положено сеньору в Гугеле, проводит больше времени в Gerrit, чем в IDE. А там как раз будет дифф без подсветки и прочего. А тащить ветку локально чтобы посмотреть на нее через IDE это слишком много телодвижений для уважаемого человека.
Слуга ваш покорный пострадал на прошлой работе в попытках аргументированно объяснить, что код пишет 50 человек и каждый день, а ревью делают 4 и только перед финалом. И исходя из этого раскладывать компонент по 6 местам и фигачить полукилометровые имена с префиксами несколько иррационально. Тем более что за 12 месяцев ни каких замечаний от оных уважаемых людей, кроме соответствия гайдлайнам, я не видел. На что получил вполне ожидаемый ответ — мы есмь четыре всадника апокалипсиса, покайсо холоп и убойся гнева нашего. На том и разошлись. ;-)
apro
19.07.2017 00:51+1код пишет 50 человек и каждый день, а ревью делают 4
А почему всего 4? Всего четыре подсистемы с 4 владельцами?
Просто у нас перекрестное ревью, и т.к. в команде все "сеньоры",
то аппроксимируя на ваши цифры 50 пишут и 50 проводят ревью
и только перед финалом
перед каким финалом, типа неделю разрабатываешь в отдельной ветке, а
потом на review отправляешь?
фигачить полукилометровые имена с префиксами
полукилометровые из-за одной буквы
m
вначале?zagayevskiy
19.07.2017 19:21+1У нас тоже перекрёстные ревью, в основном народ смотрит дифф без подсветки. И большинство проголосовало за избавление от префикса m. Что мы делаем не так?
borv
19.07.2017 22:58а почему всего четыре
потому что так у них повелось. См про качество этого процесса в том же параграфе.
перед каким финалом
pull request / git workflow. Ревью делаются на PR.
полукилометровые из-за одной буквы m
нет, из-за naming conventions у компонентов и методов. Типа PublicCampaignAnalyticsEventTransitiveViewFactory::analyticsEventCreationTimestamp. Это в общем из той же оперы.
Steed
19.07.2017 15:09+1… а код эти 50 человек пишут одноразовый, поэтому не может возникнуть необходимости разбираться в нем через год (тем более другому разработчику0...
borv
19.07.2017 23:04Одно с другим слабо связано, как отмечено выше. Если на ревью проверяется главным образом стиль кодирования и NPE, на качество кода оно слабо влияет.
avost
18.07.2017 17:49+1Если программист, читая код метода, не может вспомнить употребил ли он здесь поле, параметр или локальную переменную, значит он что-то сделал не так. Например, написал слишком длинный и/или сложный метод. Такие иногда встречаются, но именно иногда и это повод провести рефакторинг или снабдить код комментариями. Но точно не повод поганить весь этот и остальной код бесполезным префиксом m. Он бы ещё доллар из похапе догадался притащить...
soniq
18.07.2017 22:23+4Иногда программист не может вспомнить, используется тут поле или параметр, не потому что метод сложный. Просто он видит этот код первый раз в жизни.
avost
19.07.2017 00:52+1И что, вот впервые видит и сразу начинает читать код прямо с середины метода не интересуясь ни сигнатурой метода, ни тем, что там было в начале? Позвольте поинтересоваться, а с какой неведомой целью этот ваш "программист" занимается настолько бестолковой деятельностью? От бессонницы спасается? Тогда ему абсолютно всё-равно какие там переменные параметры, а какие — поля.
zuwr2t
19.07.2017 06:53+1Исправление нпе в легаси по логу от клиента. Открыл, нашел строку, исправил и забыл.
kolipass
19.07.2017 07:49Где тонко — там и рвётся
Всегда стараюсь тушить на корню такие фиксы: обязательно нужно разбираться во всей системе, познать предпосылки и причину аварийного состояния.
Добавить проверку на нул, это не исправить, это отодвинуть ошибку в другое место. Авось, в другом месте и не упадёт, не космолёт же пишем?zuwr2t
19.07.2017 07:56+2Вам не заплатят за анализ миллиона строк легаси кода из-за ошибки допущенной 5 лет назад, но впервые проявишейся.
И в 99% случаев нпе это просто нпе.kolipass
19.07.2017 08:09+7Профессионал всегда делает работу хорошо и до конца, не зависимо от бюджета. Или в другой формулировке: если ты не можешь сделать работу хорошо за небольшие деньги, ты и за большие не сможешь.
Как код становится 5-ти летним легаси? Да вот так, когда его затыкают проверками на npe, хотя потратив больше времени, можно слегка отрефакторить задев более высокий слой. И, быть может, проверка не понадобится, такая ситуация уйдёт сама собой.
NPE это симптом, а не болезнь.zuwr2t
19.07.2017 10:56+1НПЕ это просто ошибка.
Код становится 5-ти летним легаси через 5 лет. Ставить костыли или вообще как-то шевелиться для этого не нужно.
Про сияющие доспехи профессионалов проигнорирую.khim
19.07.2017 13:09Код становится 5-ти летним легаси через 5 лет.
Код становится 5-ти летним легаси после 5 лет втыкания костылей. Глядя на код в нашем проекте 3х летней давности (иногда нужно править ошибки в старых ветках) мне плакать иногда хочется, а с современным его состоянием — нет. Это, собственно, и отличает профессионала от непрофессионала. «Сиять» для этого не нужно, нужно работать.
zagayevskiy
20.07.2017 12:05NPE это не просто ошибка. В том плане, что скорее всего настоящая ошибка находится совсем не в той строке, которую вы в логах увидели, а где-то выше по стеку. И это, скорее всего, логическая ошибка.
Flammar
18.07.2017 19:11«Как попытаться убить платформу Android»…
Зачем венгерская нотация в статически типизированных языках???khim
18.07.2017 20:27+3Зачем венгерская нотация в статически типизированных языках???
Для того, чтобы указать в ней то, что не указано в типе?
Никогда не понимал использованиеlpsz
(а особенноwParam
для 64-битного значения). Но возможность отличатьmLength
отlength
— не кажется мне бесполезным. Типы-то у них совпадают… а подсветка, всё-таки, не является частью языка.
Другое дело, что подчёркивание в конце мне нравится больше — хотя это уже совсем по HN…soniq
18.07.2017 22:34Учитывая, что те же строки бывают и C-string, и BStr, и ANSI, и Unicode, и const, и out. И ещё черта лысого, а C++ легко кастит все эти типы туда-сюда, от такой нотации много пользы.
khim
19.07.2017 01:11Если «C++ легко кастит все эти типы туда-сюда» и при этом программа работает — то какая вам разница что конкртно там используется? А если не работает — то кто придумал такой API?
C++ — он, как бы, в отличие от C не умеет «из коробки» преобразовывать друг в друга никак не связанные между собой типы. Его этому нужно учить. И желательно — так, чтобы работало.Antervis
19.07.2017 05:53Есть разница. Например, передать const (w)char * вместо BSTR это UB, пусть даже и скомпилируется. Кто придумал такой api? Майкрософт, который использовал венгерку
neit_kas
19.07.2017 01:51+1Но возможность отличать mLength от length — не кажется мне бесполезным.
Мне для этих целей больше this использовать понравилось. Правда C++ использую. Использование полей с this может и длиннее, но без него я знатно путался.khim
19.07.2017 02:17+1В Python, где другого способа нет — это работает, в C++/Java — нет. Потому что пропущенный
this->
не приводит к ошибке компиляции и в рантайме тоже «стреляет» не сразу. Хотя выглядит красиво, бесспорно.zagayevskiy
20.07.2017 12:06пропущенный m, как не странно, тоже не приводит к ошибке компиляции
khim
20.07.2017 17:07Только в тех случаях, когда у вас есть аналогичная переменная без «
m
». Такого лучше в функциях длиннее трёх строк (читай: конструкторы) просто не допускать. Аthis->
пропущенный компилируется всегда — и потому отсутствиюthis->
доверять нельзя никогда, что и делает его бессмысленным.
knotri
19.07.2017 13:47В javascript также — все поля и методы только через this
Когда только начинал учить после других языков — страшно бесило
Но сейчас (я стал фронтенд-ом) мне это очень нравится.
MrErsh
19.07.2017 07:46Похоже вы не понимаете что такое венгерская нотация. Почитайте статью подробнее и вопрос отпадёт.
Antervis
18.07.2017 21:06+4Венгерская нотация явно имела повод для существования во времена программирования в блокнотах. Зачем префикс m или m_ к имени сейчас, если IDE выделяет поля класса цветом? Пользуюсь лидирующим _ для полей в с++ только лишь для того, чтобы писать нормальные имена для геттеров: скажем, поле _initialized, геттер initialized()
Префиксы типа, аля lpwzPath, конечно, нагляднее, чем переходить к месту определения переменной в IDE, но существенно увеличивают объем кода. В итоге его становится сложнее читать попросту потому, что его много.
Вот семантическая часть полезна в программировании GUI. Это банально самый лаконичный способ именовать группы виджетов с одним общим назначениемFree_ze
19.07.2017 12:40+1Зачем префикс m или m_ к имени сейчас, если IDE выделяет поля класса цветом?
Чтобы автокомплит отфильтровал поля класса среди методов, статических полей и прочего.zagayevskiy
20.07.2017 12:08То есть вы жмёте m и дальше в списке ищете нужное имя? Или всё же пишите 2-4 первые буквы?
Free_ze
21.07.2017 13:44Если человек, придерживающийся этой нотации, хочет увидеть в автокомплите список членов типа, то он жмет «m_».
asmrnv777
18.07.2017 21:18+3Префиксы типа mObject в андроиде — зло. Нет, если пишешь код в блокноте, может и полезно, но абсолютное большинство разработчиков пользуется нормальными IDE, в которых эти префиксы только мешают, кроме того, приходится рефакторить скопипащенный код для «обычной» джавы, чтобы не перемешивать стили.
Префиксы/постфиксы типа tvName — штука полезная из-за того, что может быть, грубо говоря, TextView для имени, и может быть CheckBox для имени: они удобны, чтобы не выдумывать новые имена для объектов.
Итого: я пользуюсь постфиксами для объектов типа View (nameTv, nameEt, nameBtn и т.д.), а префиксами для полей перестал пользоваться где-то через полтора года после начала разработки под Android, когда понял, что они бесполезны.
DSolodukhin
18.07.2017 21:48+3Не встречал ни одного проекта, где мне бы захотелось использовать венгерскую нотацию.
nixel
18.07.2017 21:48+2Я понимаю, что статья про другое, но… Неужели человек, разрабатывающий гайдлайн для разработчиков не догадался увести if (Log.Debug) внутрь функции Log.d? И никаких однострочников и холиваров про скобки…
Nakosika
18.07.2017 22:24+2Андроид Апи в принципе не очень грамотные программисты пилили. Все эти жизненные циклы и отдельные способы работы с разными визуальным компонентами могли прийти в голову только бестолковому новичку.
izzholtik
18.07.2017 23:11В андроиде всё сделано так, как было проще разработчику андроида.
Nakosika
18.07.2017 23:50+2Ну ради справедливости нужно заметить что убогая виртуальная машина и ограниченность ресурсов продиктовали часть этих диких вывертов. Но большая часть все-таки на совести долбодятлов, которые до сих пор даже юнит тесты не освоили. Корпоративная культура в стиле «херак-херах и в продакшен». Я когда смотрю ридми к новым версиям саппорт лайбрари, слезы каждый раз наворачиваются — они свои несчастные фрагменты почти в каждом релизе багфиксят.
dion
18.07.2017 22:27+2Разница в том что в случае с if внутри аргументы Log.d будут вычисляться даже если логи выключены.
Iqorek
18.07.2017 22:48if намного быстрей, чем вызов функции.
grossws
19.07.2017 00:30В случае openjdk/oracle jdk зачастую if вне функции и внутри одинаковы по времени после JITа. Существенное отличие — сбор строки для логгирования (вычисление аргументов). В том же slf4j пошли путём использования интерполяции уже внутри вызова логгера.
khim
19.07.2017 01:21С первой же миллисекунды быстрее? Извините, но… Не верю. JITу нужно долго «прогреваться», «разгоняться» — и в новых версиях Java этот процесс не становится более быстрым.
А процессы в Андроиде должны умирать и рождаться незаметно для пользователя и «свежезапущенный» процесс должен работать так же, как «прогретый». Зачем такую систему вообще сотворить на Java — отдельный вопрос, но раз уж сотворили, то закладываться на JIT не стоит…grossws
19.07.2017 02:24+1С первой же миллисекунды быстрее? Извините, но… Не верю. JITу нужно долго «прогреваться», «разгоняться» — и в новых версиях Java этот процесс не становится более быстрым.
Естественно не сразу. Но логгер дёргают достаточно часто, и его методы должны прогреться довольно быстро.
А процессы в Андроиде должны умирать и рождаться незаметно для пользователя и «свежезапущенный» процесс должен работать так же, как «прогретый». Зачем такую систему вообще сотворить на Java — отдельный вопрос, но раз уж сотворили, то закладываться на JIT не стоит…
Они с ART сейчас вообще пошли в сторону AOT-компиляции. Но вообще решения по тому что лучше стоит принимать не исходя из того, что "на JIT закладываться не стоит", а исходя из результатов профилирования.
Я не занимаюсь разработкой под android, но в случае openjdk на сервере по моему опыту логгирование жрёт довольно незначительное количество ресурсов.
khim
19.07.2017 02:40Но логгер дёргают достаточно часто, и его методы должны прогреться довольно быстро.
Чтобы достичь скорости, которую даёт описанный в статье if «прогреть» нужно не логгер, а, фактически, всю программу — чтобы метод за'inline'ился и потом исчез…
Но вообще решения по тому что лучше стоит принимать не исходя из того, что «на JIT закладываться не стоит», а исходя из результатов профилирования.
Это смотря чего вы хотите добиться. Подход, описанный в статье, не только ускоряет код, но и уменьшает его. А по моему опыту тут — профилирование не работает. В типичной программе есть, как правило, участки, на выполнение которых уходит 90% времени, но нет участков, которые занимают 90% объёма.grossws
19.07.2017 02:52Чтобы достичь скорости, которую даёт описанный в статье 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);
nixel
19.07.2017 15:56я не особо разбираюсь в дебрях JIT и прочих возможностей оптимизации java-кода, но даже если это все вдруг не сработает, потери на сопровождение такого кода по всей кодовой базе приложения имхо дороже, чем потеря производительности нескольких мили-(микро?)секунд на вызове функции.
zagayevskiy
20.07.2017 12:10+1Кажется, это про оптимизацию. Не уверен, что компилятор выкинет вызов метода, даже если он пустой. А if(false) выкинет.
Iqorek
18.07.2017 22:53При всем уважении к сишникам, по моим наблюдениям, люди которые переходят с с/с++ на другие языки, еще очень долго потом тянут с собой сишные погремушки. И переучить их очень тяжело. Люди, оставайтесь на си.
khim
19.07.2017 01:24+1То же самое можно сказать про Java, Haskell и вообще любой язык программирования. Людям свойственно хотеть использовать то, что они уже знают.
На C++ код, написанный человеком с 10 годами работы на Java тоже без слёз не взглянешь. Тормоза получаются знатные.Antervis
19.07.2017 06:00+2тормоза — полбеды. Сотни new без единого delete там, где объект мог бы вообще лежать на стеке — вот по чему рефакторинг плачет
Iqorek
19.07.2017 12:23Да, при переходе с си на язык вроде java и обратно, нужно мозг менять практически целиком. У них слишком много противоположных подходов в ключевых местах.
september669
19.07.2017 07:22Так и не понял зачем было вообще изобретать свой code style, когда есть готовый общепринятый java code style?
DrLivesey
19.07.2017 11:12+2Как пример
lpwzPath
прекрасен, но это все прекрасно работает, если есть готовый LLD и нет никаких отклонений.
Приведу пример:
uint16_t mu16_InstanceId;
Предположим, у вас есть 50 строк кода где вы используете этот член класса, и на каком-то этапе вы понимаете, что 16 бит уже не катит и вы меняете тип, имя переменной и еще 50 строк кода, где она была использована (хотя семантический смысл там не поменялся).
После такого diff будет выглядеть довольно раздуто.
apro
19.07.2017 14:08+3Я понимаю что это перевод, но было бы эпично разместить это в блоге "я пиарюсь".
elmal
19.07.2017 14:55+1Странно. Я вообще начинал с венгерки. Думал что она прекрасна, позволяет избежать ошибок и т.д. Потом пересел на Java, поработал в нормальных IDE, и для меня необходимость в венгерке отпала. А после того, как пописал на языках, где есть функционал val (или auto), то есть тип слева от переменной можно не указывать, почему то пришло понимание, что это тоже очень хорошо. Пришло понимание, что нужно думать об имени переменной, а не о типе, о типе должен компилятор, а не я, постоянно помнить. В результате гораздо стало проще рефакторить а также гораздо проще читать код. Ошибаться стал меньше, чем когда венгерку использовал.
Учитывая, что сейчас я в имени никакую информацию о типах стараюсь не давать, а то и вообще типы явно не указываю, то следует ли считать, что лет 15 назад я был лучшим разработчиком, чем сейчас :)? Я ведь тогда многое что делал дополнительно, еще и когда скобочку закрывал, я в комментах писал к чему эта скобочка относится и тому подобное. А сейчас забил на это, и просто делаю методы короткими, а имена максимально понятными.
zodchiy
19.07.2017 15:08Это опыт. Большинство с опытом пишут более простой и лаконичный код на «автомате».
r_ii
19.07.2017 19:36Все эти lpsz рождались когда не было никакой подсветки синтаксиса и такая нотация была вполне оправдана. Позже контекстная подсветка появилась в Visual Assist для Visual Studio. Позже был Resharper с опцией «highlight usage». А еще позже появился Android. Насколько помню даже тогда Eclipse имел подсветку синтаксиса и наверняка умел отличить локальную переменную от поля класса. Ну если не имел, то NetBeans и Intellij Idea уж точно имели, так что не было никакой необходимости тащить этот костыть в Android.
khim
19.07.2017 19:47+1Всё проще: если чего-то не умеет Gerrit, то неважно чего там умеет NetBeans, IntelliJ Idea или Eclipse. Gerrit подсветку синтаксиса умеет, но отличать локальные переменные от полей класса — нет. Всё. Вопрос закрыт. Для разработчиков Android, разумеется.
Ваш workflow может отличаться и вам, возможно, этот префис-суффикс и не нужен…
Shtucer
Я пойму, что это «Long Pointer to String with a Zero terminator», но еще это и отхождение от гайдлайна. По гайдлайну должно быть lpszName. Знак подчеркивания есть только у "m(ember)" и "g(lobal)".
Пруф
Это всё что нам надо знать о проблеме написания и чтении гайдлайнов. :)
BalinTomsk
Есть еще s_ для статических переменных in C++.
playermet
Еще несколько раз видел a(rgument) для аргументов.
Steed
lpsz_name — корректный вариант при использовнии гайдлайна по префиксам при именовании переменных с_разделением_слов_подчеркиванием. Общий гайдлайн Microsoft включает в себя рекомендации не только по префиксам, но и по именованию (camelCase). Но нет никакой проблемы, что в проекте гайдлайн используется не целиком, а частично.
А в данном случае это, скорее всего, просто мелкая невнимательность автора, который привел не совсем удачный пример.