В моей текущей компании никто не упоминает о правильном именовании переменных, это несерьезно. Мы обсуждаем с коллегами стили именования тестов, стоит ли использовать TestCase атрибут в nUnit, спорим о целесообразности #region в C#, пишем кастомные анализаторы для своих проектов и
Осознание проблемы началось с тестового задания одного кандидата (весь код в публикации изменен, NDA).
foreach (Dot d in dots)
{
WriteToOutput(d.X, d.Y);
}
Никто особо не обратил внимание на переменную d. Собеседование, время, нервы, каждый через это проходил.
Через пару часов я наткнулся на код в sql скрипте
select u.* from Users u
Еще через несколько минут в соседнем скрипте обнаружился кусок
select u.UserName, b.Locked, d.PropertyValueStrings
from Users u
join Bindings b on b.UserId = u.UserId
join Dossiers d on d.UserId = u.UserId
where u.UserName = 'USERNAME'
Последовал диалог с автором:
— Почему ты используешь u,b,d вместо нормальных имен?
— Так короче.
Вы знаете, этот аргумент абсолютно верен. Действительно, так короче.
А как насчет
select bi.BusinessIdentifir, bia.SSAFA, IsNull(bia.Bullshit, ‘Bullshit’), bis1.*, bis2.*, bis.*
from businessItems bi
inner join businessItemsArtifacts bia on ...
inner join businessItemsSegment bis1 on ...
inner join businessItemsSegment bis2 on ...
inner join businessItemsSegment bis3 on ...
where
bia.Date = @creationDate
and bi.Staus = ‘RFW’
AND
(
(bis1.SignIn = ‘Europe’ and ss2.Limit = 42 and bis3.Connection not in (‘Towel’, ‘Galaxy’))
OR
(bis1.SignIn = ‘USA’ and ss3.Limit = 146 and bis2.Connection not in (‘Trump’, ‘Klinton’))
OR
(bis1.PNH = ‘SP’ and ss2.Limit = 21 and bis3.Connection not in (‘Stan’, ‘Kyle’, 'Cartman'))
)
Запрос и так полон специфических констант и фильтров, неужели нужно усложнить его bis1, bis2, bis3?
Но добил меня
SELECT
MFID# as MemberId,
TRIM(ACX) as FirstName,
TRIM(ABX) as LastName,
TRIM(FGS) as Suffix,
TRIM(c.DSC) as Country,
TRIM(mm.CCC) as CountryCode,
FROM {0}.mailfl
LEFT OUTER JOIN BDSMTAMDRT.MEMFLT mm ON MFID# = mm.MMID#
LEFT OUTER JOIN BDSMTAMDRT.CTRCOD c ON mm.CCC = c.CCTRY
WHERE mfid# = ?
Автор дал вменяемые имена выбираемым полям, но не поименовал таблицы.
Знаете, откуда берется эта привычка у шарпистов? Из учебной литературы.
Открываем Шилдта:
var posNums = nums.Where(n => n > 0).Select(r => r);
Открываю msdn:
IEnumerable<int> squares =
Enumerable.Range(1, 10).Select(x => x * x);
Открываю Троелсена:
List<int> evenNumbers = list.FindAll(i => (i % 2) == 0);
Metanit, professorweb — везде вылезает
numbers.Select(n => ...), teams.Select(t => ...)
А потом в коде возникают артефакты вроде
team.Select( p => p.Age > 18);
Еще одна причина появления «коротышек»: изменения в коде. Был однострочный запрос с таблицей Products, городить именования не особо нужно, оставили p. Потом добавили join на ProductGroups, появилась pg, просто чтобы не изменять текущий стиль. Потом кусок кода скопипастили в другой запрос, там join на Profiles, в итоге имеем p, pg, pr.
Вместо послесловия. На самом деле проблема вовсе не в «плохом» коде. Проблема в том, что подобные куски попадаются мне уже год, а внимания на них я обратил лишь сейчас. Возникает вопрос: сколько еще недочетов лежит на самом видном месте?
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Комментарии (52)
aquamakc
10.05.2017 10:39+10Справедливости ради многие такие «сокращения» — условно принятые сообществом соглашения. Например:
for(int i = 0; i < 10;i++){}
Сокращение? Да.
Осмысленное? Нет.
Условно принятое, как норма и применяемое повсеместно? Да.
Также и с лямбдами x.
Лично для себя выработал правило — если переменная «локальная» для одной функции (или даже для части функции — можно и сократить Dot до d. Но если уж сократил так в одном месте — давай точно такое-же сокращённое имя в других местах кода. Если переменная относительно глобальная (например, публичное свойство объекта класса) тут уж будь добр — дай осмысленное имя.Oxoron
10.05.2017 10:48Циклы — да, это уже норма. Хотя во вложенных циклах «коротышки» уже могут напрягать.
По второй части: однострочники имеют обыкновение дополняться со временем. И переменная-«коротышка» может жить и в разросшемся скрипте.aquamakc
10.05.2017 11:00+1однострочники имеют обыкновение дополняться со временем. И переменная-«коротышка» может жить и в разросшемся скрипте
А вот это уже проблема кодинга. «Спагетти-код», «Божественный объект» и другие антипаттерны.
Если работа с «коротышкой» усложняется — изменить имя не сложно. Главное этот момент определить, вот только в состоянии «потока» это сделать сложно. Как-раз для этого и надо периодически выделять время на рефакторинг.
Bonart
15.05.2017 00:16Это проблема того кто дополняет.
Пока область видимости переменной — одна строка, ей ни к чему быть длиннее одного символа.
Если программист расширил область видимости переменной, то подбор более подходящего имени — его и только его ответственность.Oxoron
15.05.2017 10:43Это вы знаете. Это я знаю. Но не факт, что это знает программист расширяющий область видимости. Не факт, что у него над душой не стоит менеджер и не твердит: «дедлайн, премия, дедлайн, премия». Не факт, что этот расширяющий программист не подумает «сохраню исходный стиль». Не факт, что он вообще использует имена длиннее одной буквы в LINQ\SQL. Не факт…
Переименовать переменную — дело минуты. Часть этих «нефактов» сразу же отпадет. Плюс вы скинете часть ответственности с того, кто будет изменять ваш код, взяв её на себя (тут я полагаю что пишущий новый код программист понимает его лучше того, кто будет этот код изменять, а значит и ответственность на нем).
В комментариях уже указали ситуации, когда хватит «коротышек». Но если противопоказаний нет — лучше использовать нормальные имена.Bonart
15.05.2017 11:46Но не факт, что это знает программист расширяющий область видимости. Не факт, что у него над душой не стоит менеджер и не твердит: «дедлайн, премия, дедлайн, премия». Не факт, что этот расширяющий программист не подумает «сохраню исходный стиль». Не факт, что он вообще использует имена длиннее одной буквы в LINQ\SQL. Не факт…
"Тебе это не понадобится". Я не буду отвечать за действия людей, которыми не руковожу. Я не буду писать больше кода, чем необходимо для решения моей задачи. Я не буду вводить читающего код в заблуждение о видимости моей переменной.
вы скинете часть ответственности с того, кто будет изменять ваш код, взяв её на себя (тут я полагаю что пишущий новый код программист понимает его лучше того, кто будет этот код изменять, а значит и ответственность на нем).
Это заведомо неверно и однозначно вредно. У изменяющего код будут другие задачи, о которых я здесь и сейчас ничего не знаю. И это ему проще изменить имя переменной для лучшей читаемости его кода.
Но если противопоказаний нет — лучше использовать нормальные имена.
Для переменных с однострочной видимостью нормальные имена — как раз односимвольные.
Разумеется, если одинаково подходят оба варианта — короткий заведомо лучший как более выразительный и менее шумный.
EndUser
10.05.2017 11:00Осмысленное — исторически из математики, как и программирование из математики.
И всегда означало integer значение и/или index.
aquamakc
10.05.2017 11:05Сдаётся мне, что и в математике это не более, чем соглашение. Как, кстати, и фигурирующая тут-же N.
Anger22
10.05.2017 11:06+1А также i-тератор, хотя с прогрессом текущих ЯП итераторы переросли в нечто большее.
Oxoron
10.05.2017 11:08Программисты далеко не всегда используют i для суммирования. На матане мы иногда интегралы через I обозначали. Так скорее i-index просто традиция с корнями из математики.
Я как-то пробовал код
for(int index = 0; index < 10; index++){}
довольно непривычно было первое время.
Houston
10.05.2017 10:44+6Всё зависит от области видимости переменной. Если это однострочник из 10 символов, то почему бы и нет? И это вполне читаемо:
IEnumerable<int> squares = Enumerable.Range(1, 10).Select(x => x * x);
Oxoron
10.05.2017 10:50-2Однострочники иногда разрастаются. См. выше.
flancer
10.05.2017 11:07+9Никто не запрещает переименовать "короткую" переменную при "разрастании" однострочника. Это косяк не того, кто однострочник составил, а того, кто его развернул.
Oxoron
10.05.2017 11:14-3Довольно спорно.
Зачем оставлять потенциальную проблему? Фикс занимает секунды.
Честно говоря, я не понимаю почему локальные переменные нужно именовать нормально, а параметры в запросах-однострочниках — необязательно.aquamakc
10.05.2017 11:26+5почему локальные переменные нужно именовать нормально, а параметры в запросах-однострочниках — необязательно
))) как известно в программировании есть 3 основных проблемы — наименование переменных и ошибка на единицу.
Иногда проще написать условную x, d или i, которая используется в 1-2 строчках, чем тратить время на придумывание и набор осмысленного имени.
poxvuibr
10.05.2017 11:29+6Честно говоря, я не понимаю почему локальные переменные нужно именовать нормально, а параметры в запросах-однострочниках — необязательно.
Чем дальше использование переменной находится от её объявления, тем подробнее должно быть имя переменной. В однострочниках всегда понятно, что это за переменная, потому что её прямо в этой строчке и объявили.
Oxoron
10.05.2017 16:24Я бы добавил еще один фактор: чем больше переменных задействовано в скоупе, тем больше резона именовать их правильно (чем больше коротышек i, j, k, l тем легче ошибиться).
Bonart
15.05.2017 00:18чем больше переменных задействовано в скоупе
У однострочника (и его локальных переменных) скоуп — одна строка.
Чем больше переменных в скоупе — тем больше резона разбить его на несколько.
Eltaron
10.05.2017 20:24+4Зачем решать проблему, которая проблемой не является? Зачем усложнять восприятие куска кода и добавлять лишнюю информацию туда, где и без неё любой программист разберется за мгновение? Ну серьёзно, лямбда из пяти символов воспринимается махом, с одного взгляда, и чуть ли не периферическим зрением. И наверняка задействуются при этом совсем иные участки мозга, чем при чтении 25-символьной лямбды с офигенно подробным неймингом.
Вот когда разрастется однострочник — отрефакторите. А решать несуществующие проблемы — это преждевременная оптимизация, которая корень сами знаете чего. Или вы думали, что оптимизация бывает только по скорости?
fogone
10.05.2017 10:44А мне короткое имя в лямбдах в одно выражение вполне ок. В котлине вон есть it и тоже неплохо для простых выражений.
poxvuibr
10.05.2017 11:24+5В статье пример с SQL запросом. Сколько я видел этих самых запросов — имена таблиц всегда сокращены. Вроде бы это неправильно, потому что именна переменных должны быть осмысленными. Но почему-то пишут именно так. Со временем я поймал себя на том, что тоже так пишу. То ли потому что писать меньше, что как-то глупо, то ли потому, что букв на экране меньше и, соответственно, меньше мусора, а может быть потому, что сокращения на проекте складываются всем понятные. Не знаю точно. Но так вот выходит.
P. S. Поля у запросов поименованы потому, что они попадут в названия колонок результирующей таблицы. Псевдонимы таблиц туда не попадают.
Eldhenn
10.05.2017 11:38+8Потому что это удобно. Потому что в среднем запросе каждую таблицу надо упомянуть десяток-другой раз, и если каждый раз писать BusinessItemsArtifact — запрос превратится в нечитаемую кашу. Обычно в пределах запроса таблиц не очень много, и контекст User u, Person p или BusinessItemsArtifact bi1 не вызывает сложностей.
Evergray
11.05.2017 10:13+1Добавлю к каше масла :-). Достаточно попробовать написать schema bound view или функцию в MSSQL, где обязательно указывать имя схемы. И будет не User.Name, а MySchema.User.Name для каждого поля. А ещё табличка с пробелом в названии. Вроде dbo.[Order Details].ProductID. Короткие алиасы весь этот визуальный шум убирают.
И при изменении структуры БД удобнее рефакторить — меньше изменений делать нужно.
KitScribe
10.05.2017 11:44There are only two hard things in Computer Science: cache invalidation and naming things.
Phil KarltonНу, в приницпе, всё зависит и от типа переменной и от длины кода.
Если x'ом назвать экземпляр класса, то почему нет? Ничего страшного в этом я не вижу для читаемости. С учётом того, какие атрибуты икс будет иметь и что у него будет вызываться и так будет понятно что это за переменная.
Но если, конечно, делать какой-нибудь специфический счётчик или наполнять класс атрибутами, то там уж лучше давать обдуманные и логичные имена.
terrier
10.05.2017 12:26+4Да, в SQL сокращают имена таблиц до одной или нескольких букв. Это традиция, она устраивает большинство — добро пожаловать в одну из самых консервативных областей разработки. Устраивайтесь поудобнее, с опытом привыкнете. Если вы внезапно забыли настроить свой инструмент разработки, чтобы он вам удобно подсвечивал расшифровки сокращений — самое время это сделать.
martin_wanderer
10.05.2017 15:50Мне кажется, эта традиция имеет некие основание: структура таблиц меняется мало, а кода для работы с ними пишется много, и одно-двух-трехбуквенные сокращения становятся общеупотребительными на проекте.
Tishka17
10.05.2017 18:42+1дело в том, что например в Oracle есть жесткие ограничения на длину идентификатора. Если использовать нормальные имена — на раз вылетаешь за ограничения.
michael_vostrikov
10.05.2017 13:26+7Где-то читал (может у Макконнелла), что короткие имена дают техническим переменным, которые нужны для организации работы программы, а не для моделирования предметной области. И на мой взгляд это правильно. Чем меньше у них семантики, тем меньше они обращают на себя внимание. Алиасы таблиц в SQL относятся сюда же, они используются для указания движку, какое поле имеется в виду.
Сравните:
for (int i = 0; i < users.Count; i++) { var user = users[i]; ... } foreach (var user in users) { ... }
Поменяли тип цикла, техническая переменная ушла в движок языка.
martin_wanderer
10.05.2017 15:46Поддерживаю. Зашел сказать, что алиасы-коротышки в SQL — это хорошо и правильно: объявлены рядом, область действия — только сам запрос. Иначе они вообще не нужны — кроме случая нескольких джойнов к одной таблице можно просто использовать само имя таблицы.
SbWereWolf
10.05.2017 14:41+1применение в качестве альясов супер обрезанных имён в SQL запросах это тупо экономия места на экране.
учитывая что альяс имеет смысл только внутри запроса, и не имеет смысла внутри программы, как бы не сильно сложно на время чтения запроса в голове уложить пару сокращений.
Если не сокращать, то будет у меня имя альяса 20 символов и имя поля ещё 20 символов, итого 40 символов на ровно одно поле, это пол строки, для экрана широкоформатника — треть, на мой вкус жирно, для одного поля столько от строки отъедать.
Запросы не всегда в две строки пишутся, для меня это как правило джоины от двух до пяти таблиц, иногда с формулами во фразе SELECT, и подзапросом или двумя во фразе WHERE, раздуть всё это полными именами таблиц? ещё и так что бы альяс был говорящим в рамках запроса?
Нет я конечно очень не доволен ORACLE SQL где имя объекта ограничено в 30 символов и очень рад PostgreSQL где можно использовать аж 64 символа, но не настолько что бы в запросе повторять все 64 символа для каждого поля таблицы.
Другое дело в коде программы, там другое дело, там счётчик это counter / index / element и другие более осмысленные именования, потому что тоже вложенность бывает на пару уровней и если использовать «i», «j», «k» очень легко сбиться.
Sirikid
10.05.2017 14:45+1Может быть проблема в том, что технические ограничения языка заставляют вас вводить новые имена когда они не нужны?
-- var posNums = nums.Where(n => n > 0).Select(r => r); posNums = filter (>0) nums -- IEnumerable<int> squares = Enumerable.Range(1, 10).Select(x => x * x); squares = fmap (^2) [1..10] -- List<int> evenNumbers = list.FindAll(i => (i % 2) == 0); evenNumbers = filter even list -- team.Select( p => p.Age > 18); _ = filter ((>18) . age) team
sshikov
10.05.2017 20:16Это вас в общем случае не спасет. Да и в частном — не сильно лучше ваши варианты. Вы думаете, назначение even всегда будет таким уж очевидным? Ну т.е. идея-то правильная, а вот примеры не очень удачные.
ElectroGuard
10.05.2017 15:56Пишу на Delphi. Придерживаюсь простого правила. Все значимые переменные обязательно именую. Незначимые — временные, циклические и т.п. пишу короткими (как правило — одно-буквенными). Мне кажется оптимальный вариант.
KVL01
10.05.2017 16:22Если у точки координаты X, Y, Z, то никто в здравом уме не будет их называть как координатаПоОси<имя оси>. В этом плане мне мешают плохо именованные объекты – много писанины, за которой смысла не видно.
А вот сущности, описывающие объекты предметной области, не грех и обозвать подробнее, тем более, что название и придумывать не надо, оно уже есть в предметной области. Это действительно улучшает понимание кода.
piranuy
10.05.2017 20:30Какие то некорректные примеры «вредных» книжных примеров приведены. Если в лямбдах переменные называть длинно, то их еще и на несколько строк придется разбивать, а ведь переменная даже за их пределы не выйдет. Другое дело — какие-нибудь большие вложенные циклы, сравнимые с вашими 15ти строчными sql запросыми, где привычные i и y тоже могут боком выйти. Это тоже самое, что и с паттернами и уметь определять где с таким именованием будет лучше, а где вредно.
kxl
10.05.2017 22:11+1На C# привык в простых лямбдах ставить знак _ вместо буквы (особенно, когда без разницы — какую букву использовать). Потому, что так лучше видно, какие методы/свойства задействованы в лямбде. Из Лиспа что-ли это тянется…
Lerg
11.05.2017 01:11Могу предположить, что в будущем IDE научатся сами сокращать/восстанавливать имена переменных в зависимости от настроек. Например, когда закончил работать над каким-то методом, все его внутренние переменные и структуры коллапсируют во что-то более компактное. Так, чтобы он занимал меньше места на экране и лучшим образом показывался алгоритм/структура метода. А когда нужно снова поработать над кодом — он обратно распаковывается в читаемые осмысленные переменные и структуры.
aquamakc
11.05.2017 09:16зачем? это была бы лишняя работа. все эти имена нужны только человеку. Для машины — это адреса памяти. Тратить ресурсы на преобразование текста кода туда-обратно бессмысленно.
Eldhenn
11.05.2017 16:50Скоро мощность среднего десктопа приведёт к тому, что IDE перестанут тормозить. Это недопустимо.
YemSalat
12.05.2017 05:24зачем?
Ответ и так дан выше:
… чтобы он занимал меньше места на экране и лучшим образом показывался алгоритм/структура метода…
Тратить ресурсы на преобразование текста кода туда-обратно бессмысленно
Тратить ресурсы на раскрашивание текста кода бессмысленно — из той же оперы?aquamakc
12.05.2017 08:42+1… чтобы он занимал меньше места на экране и лучшим образом показывался алгоритм/структура метода…
И каким же образом автоматическая замена осмысленных имён на всякие x, y, z улучшит читаемость кода и понимание алгоритма?Deosis
12.05.2017 09:17И каким же образом автоматическая замена осмысленных имён на всякие x, y, z улучшит читаемость кода и понимание алгоритма?
Просите у авторов языка APL: P<{0~??a?????0,??a?!?a??}
aquamakc
12.05.2017 09:18+1давайте ещё к авторам Brainfuck`а за простотой и наглядностью синтаксиса сходим
YemSalat
16.05.2017 14:03-1И каким же образом автоматическая замена осмысленных имён на всякие x, y, z улучшит читаемость кода и понимание алгоритма?
По аналогии с тем как работает «мини-карта» кода в современных текстовых редакторах:
Она дает вам возможность взглянуть на свой код «с высоты птичьего» полета и помогает быстрее понимать структуру текущего файла.
Мне кажется нечто похожее на то что предложено выше — может позволить взглянуть на код более абстрактно.
Anger22
Это еще ладно, самое противное когда называют члены класса и локальные переменные(а еще хуже аргументы) в методе этого-же класса одинаковыми идентификаторами.
Oxoron
Это характерно для конструкторов, лечится через style-guide. Переменные\параметры именуются как var, закрытые поля — _filed, открытые поля Field.
Кстати, вы в чем разрабатываете? VS + R# вроде подсвечивают конфликты такого рода.
Anger22
До недавнего времени C++, сейчас C# скрипты для игр на Unity
Oxoron
Тогда только style-guide. Или Rider посмотреть, авторы вроде хотели его для Unity программистов предлагать.
Anger22
Ирония в том что, как раз таки те люди, которые используют райдер, допускали себе такие пошлости.
Гоовря о таких ситуациях, хотелось бы сказать что такие осмысленные названия в некоторых ситуациях создают весьма неоднозначный код в котором легко запутаться из-за одинаковых идентификаторов, и порой лучше бы они назывались одной буквой внутри метода, чем аналогично члену класса.
SbWereWolf
дать имя переменной одна из двух самых сложных проблем программирования :)
всегда по этому поводу пользуюсь переводчиками Гугла и Яндекса в поисках синонимов, что бы одна переменная от другой отличалась не приставкой / суффиксом, а целям корнем слова.