Как создавать интуитивно понятный и самодокументируемый код

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

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

Многие представители западной культуры знакомы с правило 5 секунд когда дело доходит до еды, я знаю некоторых, кто считает очень медленно 5 в этом затруднительном положении 😃. Однако когда дело доходит до кода, Джон Папа справедливо заявляет, что:

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

Джон Папа — Читаемый код

Итак, чтобы представить это в перспективе, позвольте мне

  1. Сначала проведите вас через практический пример использования рефакторинга кода.
  2. Затем мы можем обсудить добавленную стоимость и выгоды, которые это может обеспечить, и, наконец,
  3. Поделитесь несколькими полезными ресурсами, которые очень помогли в этом квесте «чистый код».

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

«Простая» история пользователя

Учитывая список отелей, выберите те, которые расположены в США, и предоставьте отфильтрованный список с номером телефона в правильном формате. Ниже приведен примерный список гостиниц.

const hotels = [
  {
    name: 'Panthers Alley',
    country: 'Wakanda',
    address: '123 Best Luck Finding, 3 Rivers, Wakanda',
    phone: '5551790871'
  },
  {
    name: 'The Golden Thread',
    country: 'USA',
    address: '5 Maple Street, Los Angeles, CA, 90000',
    phone: '2125552345'
  },
  {
    name: '12 Crowns',
    country: 'Japan',
    address: '36 Wide Alley Blvd, Tokyo',
    phone: '5558725910'
  },
  {
    name: 'Petit Paris',
    country: 'usa',
    address: '3669 Elm Street, New York, 30000',
    phone: '7075559087'
  },
  {
    name: 'The Empress Lounge',
    country: 'USA',
    address: '1 Kings Place, Atlanta, GA, 30000',
    phone: '6785553125'
  }
];

Надежный первый черновик можно было бы написать так

const USHotels = hotels
.filter(h => h.country.toLowerCase() === 'usa')
.map(h => {
    let area, prefix, line;
    let { phone } = h;

    area = phone.substr(0,3);
    prefix = phone.substr(3,3);
    line = h.phone.substr(6,4);

    const formatted = `(${area}) ${prefix} ${line}`;

    return {...h, ['phone']: formatted };
});

Если вы в состоянии прочитать вышеизложенное и без прищура понять, что происходит за 5 секунд или меньше, низкий вам поклон 🙂

Справедливости ради стоит отметить, что в предлагаемом решении есть много хорошего, например:

  • Очень описательный выбор имени константы отели США. Это неявно указывает тип значения, которое он будет содержать, что, вероятно, будет списком отелей в США.
  • Использование карта а также фильтр извлекать и преобразовывать результат в новый набор, оставляя оригинал без изменений или, говоря более технически, помогает избежать мутация исходного объекта.
  • Карта и фильтр также допускают более декларативный стиль кодирования, а не императив, который был бы неизбежен с циклы for или forEach.

Если вы хотите узнать больше об императивном и декларативном, сделайте себе одолжение и прочитайте эту замечательную статью от Тайлер МакГиннис: Императивное и декларативное программирование

Короче говоря, декларативный больше озабочен КАКИЕ тогда как императив является явным на КАК.

Это указывает нам на первую область, которая может потребовать пересмотра в нашем решении — карта блок слишком многословен и представляет собой глубокое погружение в КАК для преобразования неформатированного числа в стандарт США.

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

Я лично называю это «Инструментарий» шаг — прикольное выдуманное слово 😉 Не стесняйтесь предлагать что-то еще. Я слушаю.

Toolify: превратите свой код в небольшие единицы специализации

Давайте абстрагироваться и победить

карта блок длинный и будет основной частью нашего рефакторинга, но давайте начнем с фильтр шаг.

Давайте сначала создадим вспомогательную функцию с именем propEquals который будет беспокоиться только о том, если свойство объекта Икс равно значению у.

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

function propEquals(key, value, matchCase = false) {
    return function(obj) {
        return (!matchCase) ? obj[key] === value 
              : obj[key].toLowerCase() === value.toLowerCase();
    }
}

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

const IsWakanda = propEquals('country', 'Wakanda')(hotels[0]);
console.log(IsWakanda); // will output true

Теперь давайте добавим более конкретную функцию, которая будет нацелена только на страны США. Используя внешнюю функцию propEquals мы можем «исправить» значения аргументов всегда по умолчанию для США. Назовем эту новую функциональность Страна США.

const isUSCountry = propEquals.call(null, 'country', 'USA', true);

На простом английском мы могли бы сказать, что isUSCountry происходит от propEquals и установите значения по умолчанию родительской функции на страна как ключ , США как ценность и хотите выбрать строчные или прописные значения строки США.
Говоря «более простым» техническим языком, isUSCountry это сочинение из propEquals.

Его использование даст нам очень приятный и интуитивно понятный синтаксис:

const USHotels = hotels.filter(isUSCountry);
console.table(USHotels);

JavaScript с использованием неявного синтаксиса или бесточечной композиции

Этот синтаксис, где СШАОтели конструкция не указывает явно какие-либо аргументы, а вызывается только ссылка на функцию молчаливое программирование или же бесточечная композиция

Чем больше помощников, тем лучше

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

Сначала давайте извлечем функциональность форматирования телефона и отделим ее от того факта, что она всегда привязана к объекту. Мы должны иметь возможность форматировать число независимо от того, является оно частью объекта или нет.

Итак, ниже у нас теперь есть наш USPhoneFormat функция:

function UPhoneFormat(tel) {
    let area, prefix, line;

    area = tel.substr(0, 3);
    prefix = tel.substr(3, 3);
    line = tel.substr(6, 4);

    const formatted = `(${area}) ${prefix} ${line}`;

    return formatted;
}

Теперь давайте добавим наш последний помощник TransformProp. В основном он берет ключ и функцию преобразования и применяет преобразование значения к данному объекту.

function transformProp(key, fn) {
    return function(obj) {
        return {...obj, [key]: fn.call(null, obj[key]) };
    }
}

Теперь, следуя той же логике, что и с isUSCountry мы можем «сочинять» более конкретная функциональность, которая обрабатывает только форматирование номера телефона

const formatPhone = transformProp.call(null, 'phone', UPhoneFormat);

Большой выигрыш

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

const USHotels = hotels.filter(isUSCountry).map(formatPhone);

/ **add all the functions below the fold or better yet use imports** /

логирование СШАОтели в консоль выведет следующее:

[
  {
    "name": "The Golden Thread",
    "country": "USA",
    "address": "5 Maple Street, Los Angeles, CA, 90000",
    "phone": "(212) 555 2345"
  },
  {
    "name": "Petit Paris",
    "country": "usa",
    "address": "3669 Elm Street, New York, 30000",
    "phone": "(707) 555 9087"
  },
  {
    "name": "The Empress Lounge",
    "country": "USA",
    "address": "1 Kings Place, Atlanta, GA, 30000",
    "phone": "(678) 555 3125"
  }
]

Некоторые могут прямо сейчас почесать затылок, думая: «Это ужасно много шагов, чтобы получить по сути тот же результат. Что мы получим от этого?» Я рад, что вы спросили.

Истинный выигрыш можно выразить в том, что я назвал КРИКИ принцип. Используя его, я всегда стараюсь убедиться, что мой код:

  • С эльфийское документирование — надеюсь, это очевидно
  • С composable — выдуманное слово, но дает вам идею
  • р читаемый — сначала для человека, а затем для машин
  • Е Loquent — субъективно, но вы определяете, что есть, и придерживаетесь этого
  • А абстракционный слой — добавляйте его везде, где это имеет смысл
  • М aintainable — небольшие блоки легко тестировать
  • С масштабируемость — отдельные и общие функции легко использовать повторно

В заключение

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

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

Если вы убеждены, пришло время создать код, который КРИЧИТ!!! 🙂

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *