Неправильно именуйте непеременные

    brainFuckProgrammImage Все началось лет 8 назад. Я тогда писал одну программу для математических расчетов, и мой преподаватель указал, что я неверно именую переменные. Он был прав: x, xx, xxx сложновато различить в коде. После переименования они превратились в redSegment, greenSegment, blueSegment (в контексте задачи именование было подходящее). Потом были «Рефакторинг» Фаулера, «Совершенный код» Макконнелла, «Паттерны проектирования» банды четырех… каждый день я погружался все глубже в бездну.

    В моей текущей компании никто не упоминает о правильном именовании переменных, это несерьезно. Мы обсуждаем с коллегами стили именования тестов, стоит ли использовать 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.

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

    Only registered users can participate in poll. Log in, please.

    Встречаются ли вам плохо именованные объекты?

    Мешают ли вам плохо именованные объекты?

    Share post

    Similar posts

    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 52

      0
      Это еще ладно, самое противное когда называют члены класса и локальные переменные(а еще хуже аргументы) в методе этого-же класса одинаковыми идентификаторами.
        0
        Это характерно для конструкторов, лечится через style-guide. Переменные\параметры именуются как var, закрытые поля — _filed, открытые поля Field.
        Кстати, вы в чем разрабатываете? VS + R# вроде подсвечивают конфликты такого рода.
          +1
          До недавнего времени C++, сейчас C# скрипты для игр на Unity
            0
            Тогда только style-guide. Или Rider посмотреть, авторы вроде хотели его для Unity программистов предлагать.
              +1
              Ирония в том что, как раз таки те люди, которые используют райдер, допускали себе такие пошлости.
              Гоовря о таких ситуациях, хотелось бы сказать что такие осмысленные названия в некоторых ситуациях создают весьма неоднозначный код в котором легко запутаться из-за одинаковых идентификаторов, и порой лучше бы они назывались одной буквой внутри метода, чем аналогично члену класса.
                0
                дать имя переменной одна из двух самых сложных проблем программирования :)

                всегда по этому поводу пользуюсь переводчиками Гугла и Яндекса в поисках синонимов, что бы одна переменная от другой отличалась не приставкой / суффиксом, а целям корнем слова.
        +10
        Справедливости ради многие такие «сокращения» — условно принятые сообществом соглашения. Например:
        for(int i = 0; i < 10;i++){}
        

        Сокращение? Да.
        Осмысленное? Нет.
        Условно принятое, как норма и применяемое повсеместно? Да.
        Также и с лямбдами x.

        Лично для себя выработал правило — если переменная «локальная» для одной функции (или даже для части функции — можно и сократить Dot до d. Но если уж сократил так в одном месте — давай точно такое-же сокращённое имя в других местах кода. Если переменная относительно глобальная (например, публичное свойство объекта класса) тут уж будь добр — дай осмысленное имя.
          0
          Циклы — да, это уже норма. Хотя во вложенных циклах «коротышки» уже могут напрягать.

          По второй части: однострочники имеют обыкновение дополняться со временем. И переменная-«коротышка» может жить и в разросшемся скрипте.
            +1
            однострочники имеют обыкновение дополняться со временем. И переменная-«коротышка» может жить и в разросшемся скрипте

            А вот это уже проблема кодинга. «Спагетти-код», «Божественный объект» и другие антипаттерны.
            Если работа с «коротышкой» усложняется — изменить имя не сложно. Главное этот момент определить, вот только в состоянии «потока» это сделать сложно. Как-раз для этого и надо периодически выделять время на рефакторинг.
              0

              Это проблема того кто дополняет.
              Пока область видимости переменной — одна строка, ей ни к чему быть длиннее одного символа.
              Если программист расширил область видимости переменной, то подбор более подходящего имени — его и только его ответственность.

                0
                Это вы знаете. Это я знаю. Но не факт, что это знает программист расширяющий область видимости. Не факт, что у него над душой не стоит менеджер и не твердит: «дедлайн, премия, дедлайн, премия». Не факт, что этот расширяющий программист не подумает «сохраню исходный стиль». Не факт, что он вообще использует имена длиннее одной буквы в LINQ\SQL. Не факт…

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

                В комментариях уже указали ситуации, когда хватит «коротышек». Но если противопоказаний нет — лучше использовать нормальные имена.
                  0
                  Но не факт, что это знает программист расширяющий область видимости. Не факт, что у него над душой не стоит менеджер и не твердит: «дедлайн, премия, дедлайн, премия». Не факт, что этот расширяющий программист не подумает «сохраню исходный стиль». Не факт, что он вообще использует имена длиннее одной буквы в LINQ\SQL. Не факт…

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


                  вы скинете часть ответственности с того, кто будет изменять ваш код, взяв её на себя (тут я полагаю что пишущий новый код программист понимает его лучше того, кто будет этот код изменять, а значит и ответственность на нем).

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


                  Но если противопоказаний нет — лучше использовать нормальные имена.

                  Для переменных с однострочной видимостью нормальные имена — как раз односимвольные.
                  Разумеется, если одинаково подходят оба варианта — короткий заведомо лучший как более выразительный и менее шумный.

              0
              Осмысленное — исторически из математики, как и программирование из математики.
              И всегда означало integer значение и/или index.
              image
                0
                Сдаётся мне, что и в математике это не более, чем соглашение. Как, кстати, и фигурирующая тут-же N.
                  +1
                  А также i-тератор, хотя с прогрессом текущих ЯП итераторы переросли в нечто большее.
                    0
                    Программисты далеко не всегда используют i для суммирования. На матане мы иногда интегралы через I обозначали. Так скорее i-index просто традиция с корнями из математики.

                    Я как-то пробовал код
                    for(int index = 0; index < 10; index++){}
                    

                    довольно непривычно было первое время.
                  +6

                  Всё зависит от области видимости переменной. Если это однострочник из 10 символов, то почему бы и нет? И это вполне читаемо:


                  IEnumerable<int> squares = Enumerable.Range(1, 10).Select(x => x * x);
                    –2
                    Однострочники иногда разрастаются. См. выше.
                      +9

                      Никто не запрещает переименовать "короткую" переменную при "разрастании" однострочника. Это косяк не того, кто однострочник составил, а того, кто его развернул.

                        –3
                        Довольно спорно.
                        Зачем оставлять потенциальную проблему? Фикс занимает секунды.
                        Честно говоря, я не понимаю почему локальные переменные нужно именовать нормально, а параметры в запросах-однострочниках — необязательно.
                          +5
                          почему локальные переменные нужно именовать нормально, а параметры в запросах-однострочниках — необязательно

                          ))) как известно в программировании есть 3 основных проблемы — наименование переменных и ошибка на единицу.

                          Иногда проще написать условную x, d или i, которая используется в 1-2 строчках, чем тратить время на придумывание и набор осмысленного имени.
                            +6
                            Честно говоря, я не понимаю почему локальные переменные нужно именовать нормально, а параметры в запросах-однострочниках — необязательно.

                            Чем дальше использование переменной находится от её объявления, тем подробнее должно быть имя переменной. В однострочниках всегда понятно, что это за переменная, потому что её прямо в этой строчке и объявили.

                              0
                              Я бы добавил еще один фактор: чем больше переменных задействовано в скоупе, тем больше резона именовать их правильно (чем больше коротышек i, j, k, l тем легче ошибиться).
                                0
                                чем больше переменных задействовано в скоупе
                                У однострочника (и его локальных переменных) скоуп — одна строка.
                                Чем больше переменных в скоупе — тем больше резона разбить его на несколько.
                              0

                              .

                                +4
                                Зачем решать проблему, которая проблемой не является? Зачем усложнять восприятие куска кода и добавлять лишнюю информацию туда, где и без неё любой программист разберется за мгновение? Ну серьёзно, лямбда из пяти символов воспринимается махом, с одного взгляда, и чуть ли не периферическим зрением. И наверняка задействуются при этом совсем иные участки мозга, чем при чтении 25-символьной лямбды с офигенно подробным неймингом.

                                Вот когда разрастется однострочник — отрефакторите. А решать несуществующие проблемы — это преждевременная оптимизация, которая корень сами знаете чего. Или вы думали, что оптимизация бывает только по скорости?
                          0
                          А мне короткое имя в лямбдах в одно выражение вполне ок. В котлине вон есть it и тоже неплохо для простых выражений.
                            +5

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


                            P. S. Поля у запросов поименованы потому, что они попадут в названия колонок результирующей таблицы. Псевдонимы таблиц туда не попадают.

                              +8
                              Потому что это удобно. Потому что в среднем запросе каждую таблицу надо упомянуть десяток-другой раз, и если каждый раз писать BusinessItemsArtifact — запрос превратится в нечитаемую кашу. Обычно в пределах запроса таблиц не очень много, и контекст User u, Person p или BusinessItemsArtifact bi1 не вызывает сложностей.
                                +1
                                Добавлю к каше масла :-). Достаточно попробовать написать schema bound view или функцию в MSSQL, где обязательно указывать имя схемы. И будет не User.Name, а MySchema.User.Name для каждого поля. А ещё табличка с пробелом в названии. Вроде dbo.[Order Details].ProductID. Короткие алиасы весь этот визуальный шум убирают.

                                И при изменении структуры БД удобнее рефакторить — меньше изменений делать нужно.
                              0
                              There are only two hard things in Computer Science: cache invalidation and naming things.

                              Phil Karlton

                              Ну, в приницпе, всё зависит и от типа переменной и от длины кода.


                              Если x'ом назвать экземпляр класса, то почему нет? Ничего страшного в этом я не вижу для читаемости. С учётом того, какие атрибуты икс будет иметь и что у него будет вызываться и так будет понятно что это за переменная.


                              Но если, конечно, делать какой-нибудь специфический счётчик или наполнять класс атрибутами, то там уж лучше давать обдуманные и логичные имена.

                                +4
                                Да, в SQL сокращают имена таблиц до одной или нескольких букв. Это традиция, она устраивает большинство — добро пожаловать в одну из самых консервативных областей разработки. Устраивайтесь поудобнее, с опытом привыкнете. Если вы внезапно забыли настроить свой инструмент разработки, чтобы он вам удобно подсвечивал расшифровки сокращений — самое время это сделать.
                                  0
                                  Мне кажется, эта традиция имеет некие основание: структура таблиц меняется мало, а кода для работы с ними пишется много, и одно-двух-трехбуквенные сокращения становятся общеупотребительными на проекте.
                                    +1

                                    дело в том, что например в Oracle есть жесткие ограничения на длину идентификатора. Если использовать нормальные имена — на раз вылетаешь за ограничения.

                                    +7

                                    Где-то читал (может у Макконнелла), что короткие имена дают техническим переменным, которые нужны для организации работы программы, а не для моделирования предметной области. И на мой взгляд это правильно. Чем меньше у них семантики, тем меньше они обращают на себя внимание. Алиасы таблиц в SQL относятся сюда же, они используются для указания движку, какое поле имеется в виду.


                                    Сравните:


                                    for (int i = 0; i < users.Count; i++)
                                    {
                                        var user = users[i];
                                        ...
                                    }
                                    
                                    foreach (var user in users)
                                    {
                                        ...
                                    }

                                    Поменяли тип цикла, техническая переменная ушла в движок языка.

                                      0
                                      Поддерживаю. Зашел сказать, что алиасы-коротышки в SQL — это хорошо и правильно: объявлены рядом, область действия — только сам запрос. Иначе они вообще не нужны — кроме случая нескольких джойнов к одной таблице можно просто использовать само имя таблицы.
                                      +1
                                      применение в качестве альясов супер обрезанных имён в SQL запросах это тупо экономия места на экране.
                                      учитывая что альяс имеет смысл только внутри запроса, и не имеет смысла внутри программы, как бы не сильно сложно на время чтения запроса в голове уложить пару сокращений.

                                      Если не сокращать, то будет у меня имя альяса 20 символов и имя поля ещё 20 символов, итого 40 символов на ровно одно поле, это пол строки, для экрана широкоформатника — треть, на мой вкус жирно, для одного поля столько от строки отъедать.
                                      Запросы не всегда в две строки пишутся, для меня это как правило джоины от двух до пяти таблиц, иногда с формулами во фразе SELECT, и подзапросом или двумя во фразе WHERE, раздуть всё это полными именами таблиц? ещё и так что бы альяс был говорящим в рамках запроса?
                                      Нет я конечно очень не доволен ORACLE SQL где имя объекта ограничено в 30 символов и очень рад PostgreSQL где можно использовать аж 64 символа, но не настолько что бы в запросе повторять все 64 символа для каждого поля таблицы.

                                      Другое дело в коде программы, там другое дело, там счётчик это counter / index / element и другие более осмысленные именования, потому что тоже вложенность бывает на пару уровней и если использовать «i», «j», «k» очень легко сбиться.
                                      • UFO just landed and posted this here
                                          0

                                          Это вас в общем случае не спасет. Да и в частном — не сильно лучше ваши варианты. Вы думаете, назначение even всегда будет таким уж очевидным? Ну т.е. идея-то правильная, а вот примеры не очень удачные.

                                          0
                                          Пишу на Delphi. Придерживаюсь простого правила. Все значимые переменные обязательно именую. Незначимые — временные, циклические и т.п. пишу короткими (как правило — одно-буквенными). Мне кажется оптимальный вариант.
                                            0
                                            Если у точки координаты X, Y, Z, то никто в здравом уме не будет их называть как координатаПоОси<имя оси>. В этом плане мне мешают плохо именованные объекты – много писанины, за которой смысла не видно.

                                            А вот сущности, описывающие объекты предметной области, не грех и обозвать подробнее, тем более, что название и придумывать не надо, оно уже есть в предметной области. Это действительно улучшает понимание кода.
                                              0
                                              Какие то некорректные примеры «вредных» книжных примеров приведены. Если в лямбдах переменные называть длинно, то их еще и на несколько строк придется разбивать, а ведь переменная даже за их пределы не выйдет. Другое дело — какие-нибудь большие вложенные циклы, сравнимые с вашими 15ти строчными sql запросыми, где привычные i и y тоже могут боком выйти. Это тоже самое, что и с паттернами и уметь определять где с таким именованием будет лучше, а где вредно.
                                                +1
                                                На C# привык в простых лямбдах ставить знак _ вместо буквы (особенно, когда без разницы — какую букву использовать). Потому, что так лучше видно, какие методы/свойства задействованы в лямбде. Из Лиспа что-ли это тянется…
                                                  0
                                                  Могу предположить, что в будущем IDE научатся сами сокращать/восстанавливать имена переменных в зависимости от настроек. Например, когда закончил работать над каким-то методом, все его внутренние переменные и структуры коллапсируют во что-то более компактное. Так, чтобы он занимал меньше места на экране и лучшим образом показывался алгоритм/структура метода. А когда нужно снова поработать над кодом — он обратно распаковывается в читаемые осмысленные переменные и структуры.
                                                    0
                                                    зачем? это была бы лишняя работа. все эти имена нужны только человеку. Для машины — это адреса памяти. Тратить ресурсы на преобразование текста кода туда-обратно бессмысленно.
                                                      0
                                                      Скоро мощность среднего десктопа приведёт к тому, что IDE перестанут тормозить. Это недопустимо.
                                                        0
                                                        зачем?

                                                        Ответ и так дан выше:
                                                        … чтобы он занимал меньше места на экране и лучшим образом показывался алгоритм/структура метода…


                                                        Тратить ресурсы на преобразование текста кода туда-обратно бессмысленно

                                                        Тратить ресурсы на раскрашивание текста кода бессмысленно — из той же оперы?
                                                          +1
                                                          … чтобы он занимал меньше места на экране и лучшим образом показывался алгоритм/структура метода…

                                                          И каким же образом автоматическая замена осмысленных имён на всякие x, y, z улучшит читаемость кода и понимание алгоритма?
                                                            0
                                                            И каким же образом автоматическая замена осмысленных имён на всякие x, y, z улучшит читаемость кода и понимание алгоритма?

                                                            Просите у авторов языка APL: P←{0~¨⍨a⌽⊃⌽∊¨0,¨¨a∘!¨a←⌽⍳⍵}

                                                              +1
                                                              давайте ещё к авторам Brainfuck`а за простотой и наглядностью синтаксиса сходим
                                                              –1
                                                              И каким же образом автоматическая замена осмысленных имён на всякие x, y, z улучшит читаемость кода и понимание алгоритма?

                                                              По аналогии с тем как работает «мини-карта» кода в современных текстовых редакторах:


                                                              Она дает вам возможность взглянуть на свой код «с высоты птичьего» полета и помогает быстрее понимать структуру текущего файла.

                                                              Мне кажется нечто похожее на то что предложено выше — может позволить взглянуть на код более абстрактно.
                                                        0
                                                        Когда в выражении более одного сокращения — это уже плохо.

                                                        Only users with full accounts can post comments. Log in, please.