Выбираем имена для переменных с учетом грамматики

0
729
views

Перевод статьи «A Grammar-Based Naming Convention».

Как выбирать имена для переменных

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

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

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

Примечание: примеры кода, приведенные в этой статье, написаны на JavaScript, но подходят для любого языка, ведь речь идет только об именах.

Основные правила

Все переменные, функции, параметры и идентификаторы пишутся в camelCase. Константы пишутся в SCREAMING_CASE. Это важное разграничение, позволяющее с первого взгляда определять, какие переменные неизменяемы и по своей природе используются только для чтения.

В языках программирования, где неизменяемые переменные настоятельно поощряются (или даже являются обязательными), мы должны разграничивать неизменяемые переменные и истинные константы.

Любое статичное значение, не зависящее от пользовательского input или других динамичных значений, можно классифицировать как истинную константу. Например, значение PI это определенно истинная константа, поэтому ее имя должно писаться в SCREAMING_CASE. А camelCase используется для обозначения изменяемых и неизменяемых переменных, хранящих временных значения, псевдонимы, результаты вычислений и выходные данные, зависящие от выполнения программы.

// Immutable Variables
const userInput = document.getElementsByTagName('input')[0].value;
const hasDevto = /dev\.to/g.test(userInput);

// True Constants
const WEBSITE_NAME = 'dev.to';
const TAU = 2 * Math.PI;

Но следует учитывать влияние контекста. Критерий разграничения неизменяемых переменных и истинных констант может меняться в зависимости от ситуации. Например, можно использовать SCREAMING_CASE для userInput, если он будет использоваться как статичное значение на протяжении всей работы программы (даже если он может отличаться при запуске программы на разных устройствах). В конечном итоге, лишь от программиста зависит, как проводить линию размежевания между неизменяемыми переменными и истинными константами.

Семантические типы данных

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

Числа, строки и объекты

В большинстве случаев при выборе имен для чисел, строк и отдельных объектов используются наиболее подходящие имена существительные в единственном числе.

const usernameInputField = document.getElementById('username-field');
const username = nameInputField.value;
const hypotenuse = Math.sqrt(a**2 + b**2);
const profileData = {
  name: 'Presto',
  type: 'Dog'
};

Булевы значения

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

// Yes-or-no questions
const isDog = true;
const hasJavaScriptEnabled = false;
const canSupportSafari = false;
const isAdmin = false;
const hasPremium = true;

// Functions or methods that return booleans
// are also named in a similar fashion
function isOdd(num) { return Boolean(num % 2); }

Массивы и коллекции

Для имен массивов и прочих структур данных, напоминающих коллекции (например, Map и Set) используются наиболее подходящие имена существительные во множественном числе, записанные в camelCase.

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

При таком подходе соответствующая форма единственного числа для этих существительных может использоваться в качестве имен для переменных в ходе итерации.

// We use plural or collective nouns for arrays.
const dogs = [ 'Presto', 'Lucky', 'Sparkles' ];

// We can use the singular form of the
// variable name of the array
// in callback functions.
dogs.forEach(dog => console.log(dog));

// We can also use it in `for...of` loops.
for (const dog of dogs)
  console.log(dog);

// Here, we can use collective nouns
// for better readability.
const herdOfCows = [ 'Bessie', 'Bertha', 'Boris' ];
herdOfCows.forEach(cow => console.log(cow));
for (const cow of herdOfCows)
  console.log(cow);

Функции

Имена функций выбираются в привязке к их действию. Поэтому они часто состоят из двух частей: переходного глагола и объекта, на который направлено действие этого глагола. Другими словами, имена функций обычно соответствуют формуле глагол + существительное. Это говорит нам о том, что имя является командой, т. е., функцией, которую мы можем вызывать при необходимости.

function getSum(a, b) { return a + b; }
function findBanana(str) { return str.indexOf('banana'); }
function getAverage(numbers) {
  const total = numbers.reduce((prev, curr) => prev + curr);
  return total / numbers.length;
}

PowerShell, эквивалент Bash для Windows, это прекрасный пример языка, принудительно применяющего соглашение об именах для функций (или командлеты – как они называются в этом языке).

Приведенный ниже скрипт вычисляет общий объем памяти, выделенной для всех запущенных в настоящее время процессов Chrome. Синтаксис этого скрипта не самый дружественный, но в нем отлично видно обязательное использование формулы глагол + существительное для командлетов в PowerShell. Здесь задействованы только командлеты Get-Process, Where-Object и Measure-Object, но будьте уверены, что другие командлеты в PowerShell тоже соответствуют указанной формуле. Вот на этом сайте можно посмотреть их все.

# Get all processes currently running
$processes = Get-Process;

# Filter to retrive all Chrome processes
$chromeProcesses = $processes | Where-Object { $_.ProcessName -eq 'chrome' }

# Sum up all of the memory collectively
# allocated for the Chrome processes
$memoryUsage = $chromeProcesses | Measure-Object WorkingSet64 -Sum;

# Log the result to the console
"{0:F2} MB used by Chrome processes." -f ($memoryUsage.Sum / 1mb);

Классы

Для имен классов используются подходящие характерные существительные, которые пишутся в PascalCase. При взгляде на такое имя мы понимаем, что это не такая же переменная, как все другие, записанные в camelCase. Это особая переменная, где хранятся определенные пользователем типы со специальными свойствами и методами.

class User { }
class Admin extends User { }
class Moderator extends Admin { }
class Player extends User { }

Поля и методы классов

Поля классов именуются в соответствии с правилами относительно изменяемости и типов данных, о которых мы говорили ранее.

А вот имена для методов классов выбираются на манер имен для функций. Они тоже соответствуют формуле глагол + существительное, но в некоторых случаях в них может опускаться часть, описывающая объект действия (существительное). При этом подразумевается, что действие глагола направлено на экземпляр объекта класса, к которому принадлежит указанный метод.

// Class
class Player {
  constructor(name) {
    // String
    this.username = name;

    // Number
    this.level = 100;

    // Boolean
    this.isAdmin = false;

    // Array
    this.weapons = [
      'bow',
      'sword',
      'spear'
    ];
  }

  // Class Method (with noun)
  initiateBattle() { }

  // Class Method (without noun)
  attack() { }
}

Заключение

const TRUE_CONSTANT = Math.PI;
const stringName = '';
const numberName = 0;
const isBooleanName = true;
const objName = { };
const arrayNames = [ ].map(name => name);
function getFunctionName() { }
class ClassName { }

Приведенный выше отрывок кода прекрасно суммирует все мои правила относительно выбора имен. Совершенно очевидно, что на них сильно повлияли грамматические правила и семантика английского языка. Благодаря их применению процесс именования переменных и использования их типов данных стал гораздо более интуитивным.

При желании мы могли бы просто добавить ко всем переменным приставки с сокращенной пометкой о типе данных. Но таким образом имена стали бы излишне многословными. Пример вы можете видеть ниже.

// This is... eww. ❌
const NUM_TAU = 2 * Math.PI;
const str_Username = 'Some Dood';
const num_Hypotenuse = Math.sqrt(num_A**2 + num_B**2);
const boo_AdminStatus = false;
const obj_ProfileData = { };
const arr_Articles = [ ];
function fun_GetUser() { }
class Cls_Class { }

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

Язык программирования называется языком не без причины…

ОСТАВЬТЕ ОТВЕТ

Please enter your comment!
Please enter your name here