Главная страница
Навигация по странице:

  • Используйте удобопроизносимые имена

  • Избегайте схем кодирования имен

  • Избегайте мысленных преобразований

  • Выберите одно слово для каждой концепции

  • Воздержитесь от каламбуров

  • Используйте имена из пространства решения

  • Используйте имена из пространства задачи

  • Добавьте содержательный контекст

  • Создание, анализ ирефакторинг


    Скачать 3.16 Mb.
    НазваниеСоздание, анализ ирефакторинг
    Дата29.09.2022
    Размер3.16 Mb.
    Формат файлаpdf
    Имя файлаChistyj_kod_-_Sozdanie_analiz_i_refaktoring_(2013).pdf
    ТипКнига
    #706087
    страница7 из 49
    1   2   3   4   5   6   7   8   9   10   ...   49
    44
    Глава 2 . Содержательные имена
    Как участвующему в проекте программисту понять, какую из этих функций вы- зывать в конкретном случае?
    При отсутствии жестких именных схем имя moneyAmount не отличается от money
    , customerInfo не отличается от customer
    , accountData не отличается от account
    , а theMessage
    — от message
    . Записывайте различающиеся имена так, чтобы чита- тель кода понимал, какой смысл заложен в этих различиях .
    Используйте удобопроизносимые имена
    Людям удобно работать со словами . Значительная часть нашего мозга специ- ализируется на концепции слов, а слова по определению удобопроизносимы .
    Было бы обидно не использовать ту изрядную часть мозга, которая развивалась для разговорной речи . Следовательно, имена должны нормально произноситься .
    Если имя невозможно нормально произнести, то при любом его упоминании в об- суждении вы выглядите полным идиотом . «Итак, за этим би-си-эр-три-си-эн-тэ у нас идет пи-эс-зэт-кью, видите?» А это важно, потому что программирование является социальной деятельностью .
    В одной известной мне компании используется переменная genymdhms
    (дата ге- нерирования, год, месяц, день, час, минуты и секунды), поэтому программисты упоминали в своих разговорах «ген-уай-эм-ди-эйч-эм-эс» . У меня есть противная привычка произносить все так, как написано, поэтому я начал говорить «генъя- мадда-химс» . Потом переменную начали так называть многие проектировщи- ки и аналитики, и это звучало довольно глупо . Впрочем, мы делали это в шутку .
    Но как бы то ни было, мы столкнулись с типичным примером неудачного выбо- ра имен . Новым разработчикам приходилось объяснять смысл переменных, по- сле чего они начинали изъясняться дурацкими неестественными словами вме- сто нормальной разговорной речи . Сравните:
    class DtaRcrd102 {
    private Date genymdhms; private Date modymdhms;
    private final String pszqint = "102";
    /* ... */
    };
    и class Customer {
    private Date generationTimestamp; private Date modificationTimestamp;;
    private final String recordId = "102";
    /* ... */
    };
    Теперь становится возможным осмысленный разговор: «Эй, Майк, глянь-ка на эту запись! В поле временного штампа заносится завтрашняя дата! Разве такое возможно?»
    44

    Избегайте схем кодирования имен
    45
    Выбирайте имена, удобные для поиска
    У однобуквенных имен и числовых констант имеется один специфический не- достаток: их трудно искать в большом объеме текста .
    Строка
    MAX_CLASSES_PER_STUDENT
    отыскивается легко, а с числом 7 могут возник- нуть проблемы . Система поиска находит эту цифру в именах файлов, в опреде- лениях констант и в различных выражениях, где значение используется с совер- шенно другим смыслом . Еще хуже, если константа представляет собой длинное число, в котором были случайно переставлены цифры; в программе появляется ошибка, которая одновременно скрывается от поиска .
    Также не стоит присваивать имя e
    переменной, которая может использоваться при поиске . Самая распространенная буква английского алфавита с большой ве- роятностью встречается в любом текстовом фрагменте каждой программы . В этом отношении длинные имена лучше коротких, а имена, удобные для поиска, луч- ше констант в коде .
    Лично я считаю, что однобуквенные имена могут использоваться ТОЛЬКО для локальных переменных в коротких методах . Длина имени должна соответство-
    вать размеру его области видимости [N5]
    . Если переменная или константа мо- жет встречаться или использоваться в нескольких местах кодового блока, очень важно присвоить ей имя, удобное для поиска . Снова сравните:
    for (int j=0; j<34; j++) {
    s += (t[j]*4)/5;
    }
    и int realDaysPerIdealDay = 4;
    const int WORK_DAYS_PER_WEEK = 5;
    int sum = 0;
    for (int j=0; j < NUMBER_OF_TASKS; j++) {
    int realTaskDays = taskEstimate[j] * realDaysPerIdealDay;
    int realTaskWeeks = (realdays / WORK_DAYS_PER_WEEK);
    sum += realTaskWeeks;
    }
    Имя sum в этом фрагменте не слишком содержательно, но по крайней мере его удобно искать . Сознательное присваивание имен увеличивает длину функции, но подумайте, насколько проще найти
    WORK_DAYS_PER_WEEK
    , чем искать все вхождения цифры 5 и фильтровать список до позиций с нужным смыслом .
    Избегайте схем кодирования имен
    У нас и так хватает хлопот с кодированием, чтобы искать новые сложности . Ко- дирование информации о типе или области видимости в именах только создает новые хлопоты по расшифровке . Вряд ли разумно заставлять каждого нового работника изучать очередной «язык» кодирования — в дополнение к изучению
    45

    46
    Глава 2 . Содержательные имена
    (обычно немалого) объема кода, с которым он будет работать . Это только услож- няет его работу при попытке решения задачи . Как правило, кодированные имена плохо произносятся и в них легко сделать опечатку .
    Венгерская запись
    В доисторические времена, когда в языках действовали ограничения на дли- ну имен, мы нарушали это правило по необходимости — и не без сожалений .
    В Fortran первая буква имени переменной обозначала код типа . В ранних верси- ях BASIC имена могли состоять только из одной буквы и одной цифры . Венгер- ская запись (HN, Hungarian Notation) подняла эту проблему на новый уровень .
    Венгерская запись играла важную роль во времена Windows C API, когда про- граммы работали с целочисленными дескрипторами (handle), длинными указа- телями, указателями на void или различными реализациями «строк» (с разным применением и атрибутами) . Компиляторы в те дни не поддерживали проверку типов, поэтому программистам были нужны «подсказки» для запоминания типов .
    В современных языках существует куда более развитая система типов, а компи- ляторы запоминают типы и обеспечивают их соблюдение . Более того, появилась тенденция к использованию меньших классов и более коротких функций, чтобы программисты видели точку объявления каждой используемой переменной .
    Java-программисту кодировать типы в именах не нужно . Объекты обладают силь- ной типизацией, а рабочие среды развились до такой степени, что могут выявить ошибку типа еще до начала компиляции! Таким образом, в наши дни венгерская запись и другие формы кодирования типов в именах превратились в обычные пережитки прошлого . Они усложняют изменение имени или типа переменных, функций и классов . Они затрудняют чтение кода . Наконец, они повышают риск того, что система кодирования собьет с толку читателя кода .
    PhoneNumber phoneString;
    // Имя не изменяется при изменении типа!
    Префиксы членов классов
    Префиксы m_
    , которыми когда-то снабжались переменные классов, тоже стали ненужными . Классы и функции должны быть достаточно компактными, чтобы вы могли обходиться без префиксов . Также следует использовать рабочую среду с цветовым выделением членов классов, обеспечивающим их наглядную иден- тификацию:
    public class Part { private String m_dsc; // Текстовое описание void setName(String name) {
    m_dsc = name;
    }
    }
    _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
    46

    Избегайте мысленных преобразований
    47
    public class Part {
    String description;
    void setDescription(String description) { this.description = description;
    }
    }
    Кроме того, люди быстро учатся игнорировать префиксы (и суффиксы), чтобы видеть содержательную часть имени . Чем больше мы читаем код, тем реже заме- чаем префиксы . В конечном итоге префикс превращается в невидимый балласт, характерный для старого кода .
    Интерфейсы и реализации
    Иногда в программах встречается особый случай кодирования . Допустим, вы строите АБСТРАКТНУЮ ФАБРИКУ для создания геометрических фигур . Фа- брика представляет собой интерфейс, который реализуется конкретным классом .
    Как их назвать?
    IShapeFactory и
    ShapeFactory
    ? Я предпочитаю оставлять имена интерфейсов без префиксов . Префикс
    I
    , столь распространенный в старом коде, в лучшем случае отвлекает, а в худшем — передает лишнюю информацию . Я не собираюсь сообщать своим пользователям, что они имеют дело с интерфейсом .
    Им достаточно знать, что это
    ShapeFactory
    , то есть фабрика фигур . Следовательно, при необходимости закодировать в имени либо интерфейс, либо реализацию, я выбираю реализацию . Имя
    ShapeFactoryImp
    , или даже уродливое
    CShapeFactory
    , все равно лучше кодирования информации об интерфейсе .
    Избегайте мысленных преобразований
    Не заставляйте читателя мысленно преобразовывать ваши имена в другие, уже известные ему . Обычно эта проблема возникает из-за нежелания использовать понятия как из пространства задачи, так и из пространства решения .
    Такая проблема часто возникает при использовании однобуквенных имен пере- менных . Конечно, счетчик цикла можно назвать i
    , j
    или k
    (но только не l
    !), если его область видимости очень мала, и он не конфликтует с другими именами .
    Это связано с тем, что однобуквенные имена счетчиков циклов традиционны .
    Однако в большинстве других контекстов однобуквенные имена нежелательны; в сущности, вы создаете временный заменитель, который должен быть мысленно преобразован пользователем в реальную концепцию . Нет худшей причины для выбора имени c
    , чем та, что имена a
    и b
    уже заняты .
    Как правило, программисты весьма умны . А умные люди иногда любят показы- вать мощь интеллекта, демонстрируя свои способности к мысленному жонглиро- ванию . В конце концов, если вы помните, что переменная r
    содержит URL-адрес с удаленным хостом и схемой, преобразованный к нижнему регистру, это совер- шенно очевидно свидетельствует о вашем уме .
    47

    48
    Глава 2 . Содержательные имена
    Одно из различий между умным и профессиональным программистом заклю- чается в том, что профессионал понимает: ясность превыше всего . Профессио- налы используют свою силу во благо и пишут код, понятный для других людей .
    Имена классов
    Имена классов и объектов должны представлять собой существительные и их комбинации:
    Customer
    ,
    WikiPage
    ,
    Account и
    AddressParser
    . Старайтесь не использо- вать в именах классов такие слова, как
    Manager
    ,
    Processor
    ,
    Data или
    Info
    . Имя клас- са не должно быть глаголом .
    Имена методов
    Имена методов представляют собой глаголы или глагольные словосочетания: postPayment
    , deletePage
    , save и т . д . Методы чтения/записи и предикаты образуют- ся из значения и префикса get
    , set и is согласно стандарту javabean
    1
    string name = employee.getName();
    customer.setName("mike");
    if (paycheck.isPosted())...
    При перегрузке конструкторов используйте статические методы-фабрики с име- нами, описывающими аргументы . Например, запись
    Complex fulcrumPoint = Complex.FromRealNumber(23.0);
    обычно лучше записи
    Complex fulcrumPoint = new Complex(23.0);
    Рассмотрите возможность принудительного использования таких методов; для этого соответствующие конструкторы объявляются приватными .
    Избегайте остроумия
    Если ваши имена будут излишне остроум- ными, то их смысл будет понятен только людям, разделяющим чувство юмора авто- ра — и только если они помнят шутку . Все ли догадаются, что делает функция с име- нем
    HolyHandGrenade
    ?
    2
    Конечно, это очень мило, но, возможно, в данном случае лучше
    1
    http://java .sun .com/products/javabeans/docs/spec .html .
    2
    «Святая ручная граната» — оружие огромной разрушительной силы из фильма «Монти
    Пайтон и Священный Грааль» . — Примеч. перев.
    48

    Воздержитесь от каламбуров
    49
    подойдет имя
    DeleteItems
    . Отдавайте предпочтение ясности перед развлекатель- ной ценностью .
    Остроумие часто воплощается в форме просторечий или сленга . Например, не используйте имя whack()
    вместо kill()
    . Не используйте шуточки, привязанные к конкретной культуре, — например, eatMyShorts
    1
    ()
    вместо abort()
    Выберите одно слово
    для каждой концепции
    Выберите одно слово для представления одной абстрактной концепции и при- держивайтесь его . Например, существование в разных классах эквивалентных методов с именами fetch
    , retrieve и get неизбежно создаст путаницу . Как запом- нить, к какому классу относится то или иное имя метода? К сожалению, чтобы запомнить, какой термин использовался в той или иной библиотеке или классе, нередко приходится помнить, какой компанией, группой или программистом эта библиотека была создана . В противном случае вы потратите массу времени на просмотр заголовков и предыдущих примеров кода .
    Современные рабочие среды (такие, как Eclipse и IntelliJ) предоставляют контекстно-зависимые подсказки — скажем, список методов, которые могут вы- зываться для конкретного объекта . Однако следует учитывать, что в этом спи- ске обычно не приводятся комментарии, которые вы записываете рядом с име- нами функций и списками параметров . И вам еще повезло, если в нем будут ука- заны имена параметров из объявлений функций . Имена функций должны быть законченными и логичными, чтобы программист мог сразу выбрать правильный метод без сбора дополнительной информации .
    Аналогичным образом, использование терминов controller
    , manager и driver в одной кодовой базе тоже вызывает путаницу . Чем
    DeviceManager принципи- ально отличается от
    ProtocolController
    ? Почему в двух случаях не использу- ются одинаковые термины? Такие имена создают ложное впечатление, что два объ екта обладают совершенно разными типами, а также относятся к разным классам .
    Единый, согласованный лексикон окажет неоценимую помощь программистам, которые будут пользоваться вашим кодом .
    Воздержитесь от каламбуров
    Старайтесь не использовать одно слово в двух смыслах . В сущности, обозначе- ние двух разных идей одним термином — это каламбур .
    1
    Из мультипликационного сериала «Симпсоны» . — Примеч. перев.
    49

    50
    Глава 2 . Содержательные имена
    Если следовать принципу «одно слово для каждой концепции», в программе мо- жет появиться много классов, содержащих, например, метод add
    . Пока списки па- раметров и возвращаемые значения разных методов add остаются семантически эквивалентными, все хорошо .
    Однако программист может решить использовать имя add
    «ради единообразия» независимо от того, выполняет ли этот метод добавление в прежнем смысле или нет . Допустим, программа содержит много классов с методами add
    , которые со здают новое значение сложением или конкатенацией двух существующих значений . Вы пишете новый класс с методом, помещающим свой единственный параметр в коллекцию . Стоит ли присвоить этому методу имя add
    ? На первый взгляд это выглядит последовательно, потому что в программе уже используется множество других методов add
    , но новый метод имеет другую семантику, поэтому ему лучше присвоить имя insert или append
    . Присваивая новому методу имя add
    , вы создаете нежелательный каламбур .
    Задача автора — сделать свой код как можно более понятным . Код должен вос- приниматься с первого взгляда, не требуя тщательного изучения . Ориентируй- тесь на модель популярной литературы, в которой сам автор должен доступно выразить свои мысли, а не на академическую модель, в которой ученик усерд- ным трудом постигает скрытый смысл публикации .
    Используйте имена
    из пространства решения
    Не забывайте: ваш код будут читать программисты . А раз так, не стесняйтесь ис- пользовать термины из области информатики, названия алгоритмов и паттер- нов, математические термины и т . д . Не ограничивайтесь именами исключитель- но из пространства задачи; не заставляйте своих коллег постоянно бегать к кли- енту и спрашивать, что означает каждое имя, когда соответствующая концепция уже знакома им под другим названием .
    Имя
    AccountVisitor сообщит много полезной информации программисту, знако- мому с паттерном «Посетитель» (Visitor) . И какой программист не знает, что та- кое «очередь заданий» (
    JobQueue
    )? Существует множество сугубо технических понятий, с которыми имеют дело программисты . Как правило, таким понятиям разумнее всего присваивать технические имена .
    Используйте имена
    из пространства задачи
    Если для того, что вы делаете, не существует подходящего «программизма», ис- пользуйте имя из пространства задачи . По крайней мере программист, занима-
    50

    Добавьте содержательный контекст
    51
    ющийся сопровождением кода, сможет узнать у специалиста в предметной об- ласти, что означает это имя .
    Разделение концепций из пространств задачи и решения — часть работы хоро- шего программиста и проектировщика . В коде, главным образом ориентирован- ном на концепции из пространства задачи, следует использовать имена из про- странства задачи .
    Добавьте содержательный контекст
    Лишь немногие имена содержательны сами по себе . Все остальные имена следу- ет помещать в определенный контекст для читателя кода, заключая их в классы, функции и пространства имен с правильно выбранными названиями . В крайнем случае контекст имени можно уточнить при помощи префикса .
    Допустим, в программе используются переменные с именами firstName
    , lastName
    , street
    , houseNumber
    , city
    , state и zipcode
    . Вполне очевидно, что в совокупности они образуют адрес . Но что, если переменная state встретилась вам отдельно от других переменных внутри метода? Сразу ли вы поймете, что она является ча- стью адреса?
    Контекст можно добавить при помощи префиксов: addrFirstName
    , addrLastName
    , addrState и т . д . По крайней мере читатель кода поймет, что переменные явля- ются частью более крупной структуры . Конечно, правильнее было бы создать класс с именем
    Address
    , чтобы даже компилятор знал, что переменные являются частью чего-то большего .
    Возьмем метод из листинга 2 .1 . Нужен ли переменным более содержательный контекст? Имя функции определяет только часть контекста; алгоритм предостав- ляет все остальное . При чтении функции становится видно, что три переменные number
    , verb и pluralModifier являются компонентами сообщения guessМessage
    К сожалению, контекст приходится вычислять . При первом взгляде на метод смысл переменных остается неясным .
    1   2   3   4   5   6   7   8   9   10   ...   49


    написать администратору сайта