[Перевод] О каждодневном совершенствовании JavaScript-программиста

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

vednttgaco7m2xnsp7iebtesiuo.jpeg

Выбор редактора кода


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

Я, в основном, использую Visual Studio Code. Исключения я делаю только для разработки под Android, применяя Android Studio, и для iOS-разработки, где работаю в Xcode.

VS Code — это проект Microsoft. Да, именно Microsoft, что, с моей точки зрения, звучит очень даже неплохо. Этот редактор поддерживает практически все актуальные языки программирования, для него создано огромное количество расширений, он поддерживает вывод интеллектуальных подсказок, обладает приятным интерфейсом. И он, кроме прочего, не создаёт чрезмерной нагрузки на систему (он, конечно, не «легче» Sublime Text, но, всё равно, достаточно скромен в плане системных требований).

f809bde3e4d8faaae9d12a22106bb116.png


VS Code

Раньше я работал лишь в Sublime Text (тогда VS Code не пользовался особой популярностью). Теперь же множество расширений (о которых я расскажу ниже), позволяют мне экономить массу времени, так как мне, в частности, не приходится заботиться о самостоятельном исправлении мелких ошибок в ходе работы. Среди этих расширений можно отметить такие, которые автоматически выявляют и исправляют ошибки, такие, которые форматируют код, упрощают работу с Git, дают возможность пользоваться терминалом.

Если вы пишете на PHP, то вам понравится PhpStorm. Если работаете на Python — тогда вам стоит взглянуть на PyCharm. Бесспорно то, что эти редакторы (IDE) представляют собой мощные инструменты. Но предназначены они лишь для одного языка. Я — фуллстек-разработчик, который использует JavaScript, HTML, PHP, Node.js, React, Docker. Поэтому я остановил свой выбор на VS Code, так как это — редактор с огромными возможностями, поддерживающий массу расширений и, что мне особенно нравится, содержащий систему интеллектуального автозавершения кода.

Применение ESLint


Раньше много моего времени отнимали синтаксические ошибки. Они меня, кроме того, ещё и очень расстраивали. Среди таких ошибок — нечто вроде необъявленных переменных и функций, появление значений null, пропущенные структурные элементы кода. По мере роста размеров проектов разработчик устаёт от того, что ему приходится постоянно читать большие объёмы кода. Он хуже воспринимает этот код, он, при вводе текстов программ, совершает опечатки, делает другие ошибки.

Всё изменилось тогда, когда я начал пользоваться ESLint. Это — плагин, который умеет искать ошибки в коде, проверять синтаксис, форматировать код в соответствии с популярными стандартами. Применение ESLint способствует сокращению количества ошибок в коде и помогает писать код, который просто лучше выглядит. С помощью ESLint можно проверять как обычный JavaScript-код, так и код, который пишут, используя популярные библиотеки и фреймворки — вроде React и Vue.

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

3fdc19e9d7e1bfdd63d82944365540f9.gif


Использование ESLint в VS Code

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

Подбор оптимальной структуры директорий


Хочу поделиться с вами одной идеей, которую я недавно принял на вооружение: «Не стремитесь оптимизировать структуру проекта в самом начале работы над ним».

Раньше, начиная работу над проектом, над большим или маленьким, я всегда тратил много времени, пытаясь подобрать оптимальную структуру директорий для этого проекта. Я искал и читал статьи, которые могли называться «Рекомендации по структуре папок Node.js-проектов» и «Структура React-приложений». Но я никогда не был до конца уверен в оптимальности выбранной структуры, не знал, правильно ли я организую свой код. Как результат — на всё это уходило много времени.

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

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

Если вы стремитесь к тому, чтобы ваши проекты были бы хорошо структурированными — предлагаю обратить внимание на Node.js-фреймворк NestJS. Хочу отметить, что я неплохо знаком с этим фреймворком. Он отличается очень хорошей архитектурой (она похожа на архитектуру, применяемую в AngularJS, но я не особенно люблю Angular).

Применение console.log в тех случаях, когда есть подозрения, что с кодом что-то не так


Я совершенно уверен в том, что конструкцией, которую я чаще всего использую при программировании на JavaScript, является метод console.log. Основная цель применения этого метода заключается в том, чтобы проверить данные, используемые в том или ином месте программы.

Лично я полагаю, что в программировании, независимо от используемого языка, всё, в основном, вращается вокруг данных. Поэтому, если вы сталкиваетесь с кодом, который работает не так, как ожидается, стоит проверить данные, которыми он оперирует, прибегнув к console.log.

Многие говорят, что в подобных ситуациях профессиональнее выглядит использование выражения debugger. Да и Google Chrome поддерживает средства отладки кода, возможности которых превосходят console.log. Но мне, например, всё это не нужно. Используя console.log, я, как и при применении более совершенных инструментов, знаю о том, в какой строке кода проводится проверка. С моей точки зрения, console.log быстрее и удобнее других отладочных механизмов. Кроме того, мне доводилось видеть учебные руководства, написанные известными программистами из крупных компаний. И console.log применяется даже там.

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

Своевременное комментирование кода


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

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

Но комментарии должны, во-первых, быть уместными, а во-вторых — должны хорошо выглядеть. Не нужно комментировать абсолютно всё. Если перестараться с комментариями, это усложнит чтение кода.

1fed3f19fce5492e52f8a938d551e60d.png


Код с комментариями

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

7d3078ac5733e96cd9fd103678939fcf.png


Более понятный код, в котором нет комментариев

Использование современных возможностей JavaScript


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

Новые возможности JavaScript позволяют эффективнее решать задачи, встающие перед программистами. Они позволяют писать код, который лучше выглядит, который легче читается, код, который оказывается компактнее, чем прежде.

Вот некоторые достаточно свежие JavaScript-конструкции, которые я нахожу полезными и часто использую.

// Цикл forEach
arr.forEach((item, index) => {
    // TODO
})

// Цикл for...of
for (const item of arr) {
    await something()
}

// Клонирование массива (с таким массивом можно работать без изменения исходного массива)
const arr = [1,2,3]
const newArray = arr.map(item => item * 2)
console.log(newArray)

// Фильтрация массива по условию
const arr = [1,2,3,1]
const newArray = arr.filter(item => {
    if (item === 1) { return item }
})
console.log(newArray)

// Слияние массивов
const arr1 = [1,2,3]
const arr2 = [4,5,6]
const arr3 = [...arr1, ...arr2]
console.log(arr3)

// Получение свойства объекта
const { email, address } = user
console.log(email, address)

// Копирование объектов и массивов
const obj = { name: 'my name' }
const clone = { ...obj }
console.log(obj === clone)


Отказ от промисов и коллбэков и переход на async/await


▍Недостатки промисов и коллбэков


При создании программ приходится много работать с различными API. Вот как выглядит обращение к API для получения данных, которые, например, нужно где-то вывести:

// Получить список пользователей
axios.get('/users')
.then(response => {
    console.log(response)
})
.catch(error => {
    console.log(error)
})


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

// Получить список пользователей
axios.get('/users')
.then(response => {
   console.log(response)
   // Получить адреса пользователей
   axios.get('/addresses')
    .then(response1 => {
        console.log(response1)
    })
    .catch(error1 => {
        console.log(error1)
    })
})
.catch(error => {
    console.log(error)
})


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

8afb5cfcfa7a9fb5f90ff80bd164e45c.jpg


Код с большой глубиной вложенных конструкций

▍Сильные стороны async/await


Конструкция async/await появилась в стандарте ES6 (он вышел в 2015 году). Это — альтернатива промисам и коллбэкам в обработке асинхронных операций. В этой конструкции хорошо то, что она помогает нам писать асинхронный код, который выглядит как синхронный, не содержащий вложенных конструкций.

Перепишем вышеприведённый код с использованием async/await:

async function test () {
    try {
        const users = await axios.get('/users')
        
        const addresses = await axios.get('/addresses')
    } catch (error) {
        console.log(error)
    }
}

test()


Тут стоит обратить внимание на несколько моментов:

  • Ключевое слово await всегда используется совместно с ключевым словом async.
  • При использовании асинхронных функций для перехвата и обработки ошибок используется конструкция try/catch.
  • Сущность await заключается в том, что эта конструкция ожидает возврата результата соответствующим промисом. Поэтому, если слишком увлекаться await, это может замедлить работу приложения.


Хочу обратить ваше внимание на то, что при использовании async/await, в отличие от коллбэков и промисов, ошибки можно обрабатывать с использованием конструкции try/catch. Эта конструкция, помимо async/await-ошибок, отреагирует и на другие ошибки, происходящие в соответствующем блоке кода.

Улучшение качества кода с использованием TypeScript


Сначала я программировал на C. Потом — на Java. Это — языки, очень строго относящиеся к типам данных. Они требуют от программиста чёткого и полного описания используемых им типов (string, boolean и так далее), или спецификаций доступа к полям объектов (public, private, protected). Тогда меня всё это очень утомляло. Постоянно приходилось думать о том, можно или нет обратиться к некоему свойству объекта, о том, какой тип имеет та или иная переменная. Код можно было запустить лишь для того, чтобы увидеть сообщение об ошибке, связанной с типами данных.

После перехода на JavaScript (то же самое можно сказать и о PHP, и о Python), всё это значительно упростилось. Неважно то, значение какого типа будет записано в некую переменную. Её достаточно объявить и, без лишних сложностей, ей пользоваться.

let x = 1

const test = 'This is a test'

const arr = [1, 2, 3, 4, 5]


Это было одной из тех особенностей JavaScript, которые заставили меня с первого взгляда влюбиться в этот язык. Синтаксис языка не был нагружен излишними «предрассудками», код получался аккуратнее, выглядел чище, чем код, написанный на строго типизированных языках. Однако жизнь внесла в моё восприятие JavaScript свои коррективы. Постепенно я начал понимать то, что если над проектом работает множество программистов, или если программу приходится читать через некоторое время после её создания, то код начинает выглядеть уже не таким понятным и чётким, как выглядел при его написании. Ведь в момент объявления переменной неизвестно то, значения какого типа она принимает, а из кода функции нелегко понять то, данные какого типа она возвращает…

const var1 = db.column1
const var2 = db.column2
const var3 = db.column3
const var4 = db.column4


Как разобраться в этом фрагменте кода? Должно быть, нужно прибегнуть к console.log:

const var1 = db.column1
console.log(var1) // -> string
const var2 = db.column2
console.log(var2) // -> boolean (true/false)
const var3 = db.column3
console.log(var3) // -> number
const var4 = db.column4
console.log(var4) // -> array


Не самое приятное занятие. Это, к тому же, отнимало у меня много времени. Код получался непонятным, сложности с ним возникали и у меня, и у тех, кто работал с ним после меня. Нормально ли то, что для понимания кода нужно постоянно пользоваться console.log?

Тут мне на помощь пришёл TypeScript.

Я воспринимаю TypeScript как усовершенствованную версию JavaScript. Благодаря TypeScript в JS-коде появляются чётко определённые типы (string, boolean, number и прочие), модификаторы доступа (public, private) и многое другое. Код, написанный на TypeScript, компилируется в JavaScript-код, который можно запускать там же, где запускается обычный JavaScript-код. Каких-то особых сред для запуска этого кода не требуется.

Вот пример:

class Student {
    fullName: string;
    constructor(public firstName: string, public middleInitial: string, public lastName: string) {
        this.fullName = firstName + " " + middleInitial + " " + lastName;
    }
}

interface Person {
    firstName: string;
    lastName: string;
}

function greeter(person: Person) {
    return "Hello, " + person.firstName + " " + person.lastName;
}

let user = new Student("Jane", "M.", "User");


Я узнал о TypeScript 2 года назад, но мне он тогда не понравился, мне не хотелось им пользоваться: очень уж я привык к той свободе, которую давал мне JavaScript. Порой мне хотелось попробовать TypeScript, но мне казалось, что, постоянно работая с TS-кодом, постоянно глядя на сложные и неопрятные конструкции, я рискую «поломать» себе глаза.

Но некоторое время тому назад я перешёл на TypeScript ради решения всех тех проблем JavaScript, о которых я уже рассказывал. Кроме того, движение в сторону TypeScript наблюдается во всём сообществе JavaScript-программистов. И программисты обычно довольны результатами перехода на TypeScript.

Сейчас TypeScript пользуется огромной популярностью в среде JavaScript-разработки. Создатели библиотек и фреймворков (Angular, React, Vue) обращают внимание на то, чтобы их проекты поддерживали бы использование TypeScript. Например, если кто не знает, фреймворк Vue 3 целиком переписан на TypeScript. Кроме того, TypeScript разработан компанией Microsoft, это даёт уверенность в высоком качестве данного проекта, и в том, что, применяя его, можно рассчитывать на хороший уровень поддержки.

Использование CI/CD: программирование, тестирование, развёртывание


▍Автоматизация тестирования


Если вы работаете над каким-то проектом, то рано или поздно в нём начнут появляться ошибки. Лучше всего, в ходе работы над проектами, и развивать их, и, одновременно, улучшать. Всегда стоит стремиться к тому, чтобы уделять около 20% рабочего времени улучшению кода. Единственный способ оградить себя от проблем при улучшении кода заключается в написании тестов. По крайней мере, тесты помогают сделать так, чтобы в ходе улучшений в код попадало бы как можно меньше ошибок.

И, кстати, тесты можно писать раньше, чем написан код, который проверяется с их помощью (это справедливо не только для JavaScript-разработки).

▍CI/CD — непрерывное тестирование и развёртывание проектов


CI/CD (Continuous Integration/Continuous Delivery — непрерывная интеграция/непрерывное развёртывание) — это тренд наших дней. Это — то, что помогает современным программистам писать, тестировать и развёртывать код. Делается это автоматически и непрерывно.

9d8f4ed80e5134382b02a906a9609190.png


Сведения о коде, выводимые в репозитории

На самом деле, практически все CI/CD-инструменты рассчитаны на интеграцию с GitHub, GitLab, BitBucket, и с другими подобными сервисами. В результате настройка всего этого достаточно проста. А после того, как всё настроено, при отправке кода в репозиторий запускаются соответствующие автоматизированные механизмы.

Итоги


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

А что вам помогает оставаться в хорошей JavaScript-форме?

a_bsaactpbr8fltzymtkhqbw1d4.png

© Habrahabr.ru