Лекция
Это окончание невероятной информации про идеальный код.
...
что в большинстве случаев им не нужны все настройки. Сделав их необязательными, вы предотвратите появление «жирного интерфейса».
Плохой:
class DOMTraverser { конструктор ( настройки ) { это . settings = настройки ; это . setup ( ) ; } setup ( ) { это . rootNode = это . настройки . rootNode ; это . настройки . animationModule . setup ( ) ; } traverse ( ) { // ... } } const $ = new DOMTraverser ( { rootNode : document . getElementsByTagName ( "body" ) , animationModule ( ) { } // В большинстве случаев анимация при перемещении не требуется. // ... } ) ;
Хороший:
class DOMTraverser { конструктор ( настройки ) { это . settings = настройки ; это . параметры = настройки . варианты ; это . setup ( ) ; } setup ( ) { это . rootNode = это . настройки . rootNode ; это . setupOptions ( ) ; } setupOptions ( ) { if ( this . options . animationModule ) { // ... } } traverse ( ) { // ... } } const $ = новый DOMTraverser ( { rootNode : document . getElementsByTagName ( "body" ) , параметры : { animationModule ( ) { } } } ) ;

В этом принципе говорится о двух важных вещах:
Сначала это может быть трудно понять, но если вы работали с AngularJS, вы видели реализацию этого принципа в форме внедрения зависимостей (DI). Хотя это не идентичные концепции, DIP не дает высокоуровневым модулям знать подробности своих низкоуровневых модулей и настраивать их. Это можно сделать с помощью DI. Огромным преимуществом этого является то, что уменьшается связь между модулями. Связывание - это очень плохой шаблон разработки, потому что он затрудняет рефакторинг вашего кода.
Как указывалось ранее, у JavaScript нет интерфейсов, поэтому зависящие от него абстракции являются неявными контрактами. То есть методы и свойства, которые объект / класс предоставляет другому объекту / классу. В приведенном ниже примере неявный контракт заключается в том, что любой модуль запроса для объекта InventoryTrackerбудет иметьrequestItems метод.
Плохой:
класс InventoryRequester { конструктор ( ) { это . REQ_METHODS = [ "HTTP" ] ; } requestItem ( элемент ) { // ... } } class InventoryTracker { конструктор ( элементы ) { это . items = items ; // ПЛОХО: мы создали зависимость от конкретной реализации запроса. // Нам просто нужно, чтобы requestItems зависели от метода запроса: `request` this . Requester = новый InventoryRequester ( ) ; } requestItems ( ) { это . предметы . Foreach ( пункт => { этот . запрашивающая . requestItem ( пункт ) ; } ) ; } } const inventoryTracker = new InventoryTracker ( [ "яблоки" , "бананы" ] ) ; inventoryTracker . requestItems ( ) ;
Хороший:
class InventoryTracker { конструктор ( элементы , инициатор запроса ) { this . items = items ; это . запрашивающий = запрашивающий ; } requestItems ( ) { это . предметы . Foreach ( пункт => { этот . запрашивающая . requestItem ( пункт ) ; } ) ; } } class InventoryRequesterV1 { конструктор ( ) { это . REQ_METHODS = [ "HTTP" ] ; } requestItem ( элемент ) { // ... } } class InventoryRequesterV2 { конструктор ( ) { это . REQ_METHODS = [ "WS" ] ; } requestItem ( элемент ) { // ... } } // Построив наши зависимости извне и внедрив их, мы можем легко // заменить наш модуль запроса на новый модный, использующий WebSockets. const inventoryTracker = new InventoryTracker ( [ "яблоки" , "бананы" ] , new InventoryRequesterV2 ( ) ) ; inventoryTracker . requestItems ( ) ;

Тестирование важнее доставки. Если у вас нет тестов или их недостаточно, то каждый раз, когда вы отправляете код, вы не будете уверены, что ничего не сломали. Решение о том, что составляет адекватную сумму, зависит от вашей команды, но наличие 100% покрытия (всех утверждений и ветвей) - это то, как вы достигнете очень высокой уверенности и спокойствия разработчика. Это означает, что помимо отличной среды тестирования вам также необходимо использовать хороший инструмент покрытия .
Нет оправдания тому, чтобы не писать тесты. Существует множество хороших фреймворков для тестирования JS , так что выберите ту, которую предпочитает ваша команда. Когда вы найдете тот, который работает для вашей команды, постарайтесь всегда писать тесты для каждой новой функции / модуля, которые вы вводите. Если ваш предпочтительный метод - разработка через тестирование (TDD), это прекрасно, но главное - просто убедиться, что вы достигли своих целей охвата, прежде чем запускать какую-либо функцию или проводить рефакторинг существующей.
Плохой:
импортировать assert из "assert" ; описать ( "MomentJS" , ( ) => { it ( "обрабатывает границы дат" , ( ) => { let date ; date = new MomentJS ( "01.01.2015" ) ; дата . addDays ( 30 ) ; утверждать . равно ( «31.01.2015» , дата ) ; date = new MomentJS ( "01.02.2016" ) ; дата . addDays ( 28 ) ; утверждать . равно ( «29.02.2016» , дата ) ; date = new MomentJS ( "01.02.2015" ) ; дата . addDays ( 28 ) ; утверждать . равно ( «01.03.2015» , дата ) ; } ) ; } ) ;
Хороший:
импортировать assert из "assert" ; описать ( "MomentJS" , ( ) => { it ( "обрабатывает 30-дневные месяцы" , ( ) => { const date = new MomentJS ( "1/1/2015" ) ; date . addDays ( 30 ) ; assert . равный ( "31.01.2015" , дата ) ; } ) ; it ( "обрабатывает високосный год" , ( ) => { const date = new MomentJS ( "2/1/2016" ) ; date . addDays ( 28 ) ; assert . equal ( "29.02.2016" , date ) ; } ) ; it ( "обрабатывает невисокосный год" , ( ) => { const date = new MomentJS ( "2/1/2015" ) ; date . addDays ( 28 ) ; assert . equal ( "03/01/2015" , date ) ; } ) ; } ) ;

Обратные вызовы не являются чистыми и вызывают чрезмерное количество вложений. В ES2015 / ES6 обещания являются встроенным глобальным типом. Используй их!
Плохой:
импорт { получить } из "запроса" ; import { writeFile } из "fs" ; get ( "https://en.wikipedia.org/wiki/Robert_Cecil_Martin" , ( requestErr , response , body ) => { if ( requestErr ) { console . error ( requestErr ) ; } else { writeFile ( "article.html" , тело , writeErr => { если ( writeErr ) { консоли . ошибка ( writeErr ) ; } else { console . log ( "Файл записан" ) ; } } ) ; } } ) ;
Хороший:
импорт { получить } из "запрос-обещание" ; import { writeFile } из "fs-extra" ; получить ( "https://en.wikipedia.org/wiki/Robert_Cecil_Martin" ) . then ( body => { return writeFile ( "article.html" , body ) ; } ) . then ( ( ) => { console . log ( "Файл записан" ) ; } ) . catch ( err => { console . error ( err ) ; } ) ;

Promises - очень чистая альтернатива обратным вызовам, но ES2017 / ES8 предлагает async и await, которые предлагают еще более чистое решение. Все, что вам нужно, это функция с префиксом в виде asyncключевого слова, и тогда вы можете писать свою логику императивно без thenцепочки функций. Используйте это, если можете воспользоваться функциями ES2017 / ES8 уже сегодня!
Плохой:
импорт { получить } из "запрос-обещание" ; import { writeFile } из "fs-extra" ; получить ( "https://en.wikipedia.org/wiki/Robert_Cecil_Martin" ) . then ( body => { return writeFile ( "article.html" , body ) ; } ) . then ( ( ) => { console . log ( "Файл записан" ) ; } ) . catch ( err => { console . error ( err ) ; } ) ;
Хороший:
импорт { получить } из "запрос-обещание" ; import { writeFile } из "fs-extra" ; асинхронная функция getCleanCodeArticle ( ) { попробуйте { const body = await get ( "https://en.wikipedia.org/wiki/Robert_Cecil_Martin" ) ; Await WriteFile ( "article.html" , тела ) ; консоль . log ( "Файл записан" ) ; } catch ( err ) { console . ошибка ( ERR ) ; } } getCleanCodeArticle ( )

Выброшенные ошибки - это хорошо! Они означают, что среда выполнения успешно определила, когда что-то в вашей программе пошла не так, и сообщает вам об этом, останавливая выполнение функции в текущем стеке, убивая процесс (в Node) и уведомляя вас в консоли с трассировкой стека.
Ничего не делать с обнаруженной ошибкой, это не дает вам возможности исправить эту ошибку или отреагировать на нее. Регистрация ошибки в console ( console.log) не намного лучше, поскольку часто она может потеряться в море вещей, напечатанных на консоли. Если вы заключите какой-либо бит кода в a, try/catchэто означает, что вы думаете, что здесь может произойти ошибка, и поэтому у вас должен быть план или создать путь кода на случай, когда она произойдет.
Плохой:
попробуйте { functionThatMightThrow ( ) ; } catch ( ошибка ) { console . журнал ( ошибка ) ; }
Хороший:
попробуйте { functionThatMightThrow ( ) ; } catch ( error ) { // Один вариант (более шумный, чем console.log): console . error ( ошибка ) ; // Другой вариант: notifyUserOfError ( error ) ; // Другой вариант: reportErrorToService ( error ) ; // ИЛИ сделайте все три! }
По той же причине не следует игнорировать ошибки, обнаруженные в файлах try/catch.
Плохой:
getdata ( ) . затем ( данные => { functionThatMightThrow ( data ) ; } ) . catch ( error => { console . log ( error ) ; } ) ;
Хороший:
getdata ( ) . затем ( данные => { functionThatMightThrow ( data ) ; } ) . catch ( error => { // Один вариант (более шумный, чем console.log): console . error ( error ) ; // Другой вариант: notifyUserOfError ( error ) ; // Другой вариант: reportErrorToService ( error ) ; // ИЛИ сделать все три! } ) ;

Форматирование субъективно. Как и во многих других правилах, здесь нет жесткого правила, которому вы должны следовать. Главное - НЕ СПОРЯТЬ по поводу форматирования. Есть масса инструментов для автоматизации этого. Используйте один! Споры по поводу форматирования для инженеров - пустая трата времени и денег.
Для вещей, которые не подпадают под действие автоматического форматирования (отступы, табуляции и пробелы, двойные или одинарные кавычки и т. Д.), Смотрите здесь некоторые рекомендации.
JavaScript не типизирован, поэтому использование заглавных букв многое говорит о ваших переменных, функциях и т. Д. Эти правила субъективны, поэтому ваша команда может выбирать все, что захочет. Дело в том, что независимо от того, что вы все выберете, просто будьте последовательны.
Плохой:
const DAYS_IN_WEEK = 7 ; const daysInMonth = 30 ; const songs = [ "Back In Black" , "Stairway to Heaven" , "Hey Jude" ] ; const Artists = [ "ACDC" , "Led Zeppelin" , "Битлз" ] ; function eraseDatabase ( ) { } функция restore_database ( ) { } класс животных { } класс Альпака { }
Хороший:
const DAYS_IN_WEEK = 7 ; const DAYS_IN_MONTH = 30 ; const SONGS = [ «Снова в черном» , «Лестница в небеса» , «Привет, Джуд» ] ; const ARTISTS = [ "ACDC" , "Led Zeppelin" , "Битлз" ] ; function eraseDatabase ( ) { } function restoreDatabase ( ) { } class Animal { } class Alpaca { }

Если функция вызывает другую, держите эти функции вертикально близко в исходном файле. В идеале держите абонента прямо над вызываемым. Мы склонны читать код сверху вниз, как в газете. Из-за этого сделайте так, чтобы ваш код читался именно так.
Плохой:
class PerformanceReview { конструктор ( сотрудник ) { это . сотрудник = сотрудник ; } lookupPeers ( ) { return db . поиск ( этот . сотрудник , «сверстники» ) ; } lookupManager ( ) { вернуть db . поиск ( этот . сотрудник , «менеджер» ) ; } getPeerReviews ( ) { const peers = this . lookupPeers ( ) ; // ... } perfReview ( ) { это . getPeerReviews ( ) ; это . getManagerReview ( ) ; это . getSelfReview ( ) ; } getManagerReview ( ) { const manager = это . lookupManager ( ) ; } getSelfReview ( ) { // ... } } const review = new PerformanceReview ( сотрудник ) ; обзор . perfReview ( ) ;
Хороший:
class PerformanceReview { конструктор ( сотрудник ) { это . сотрудник = сотрудник ; } perfReview ( ) { это . getPeerReviews ( ) ; это . getManagerReview ( ) ; это . getSelfReview ( ) ; } getPeerReviews ( ) { const peers = this . lookupPeers ( ) ; // ... } lookupPeers ( ) { return db . поиск ( этот . сотрудник , «сверстники» ) ; } getManagerReview ( ) { const manager = это . lookupManager ( ) ; } lookupManager ( ) { вернуть db . поиск ( этот . сотрудник , «менеджер» ) ; } getSelfReview ( ) { // ... } } const review = new PerformanceReview ( сотрудник ) ; обзор . perfReview ( ) ;

Комментарии - это извинение, а не требование. Хороший код в основном сам документирует.
Плохой:
function hashIt ( data ) { // Хеш let hash = 0 ; // Длина строки const length = data . длина ; // Цикл по каждому символу в данных for ( let i = 0 ; i < length ; i ++ ) { // Получить код символа. const char = данные . charCodeAt ( i ) ; // Создаем хэш hash = ( hash << 5 ) - hash + char ; // Преобразование в 32-битный целочисленный хэш & = hash ; } }
Хороший:
функция hashIt ( данные ) { пусть hash = 0 ; длина константы = данные . длина ; for ( пусть я = 0 ; я < длина ; я ++ ) { const char = data . charCodeAt ( i ) ; hash = ( hash << 5 ) - хеш + символ ; // Преобразование в 32-битный целочисленный хэш & = hash ; } }

Контроль версий существует не просто так. Оставьте старый код в своей истории.
Плохой:
doStuff ( ) ; // doOtherStuff (); // doSomeMoreStuff (); // doSoMuchStuff ();
Хороший:
doStuff ( ) ;

Помните, используйте контроль версий! Нет необходимости в мертвом коде, закомментированном коде и особенно в журнальных комментариях. Используйте, git logчтобы получить историю!
Плохой:
/ ** * 2016-12-20: Удалены монады, их не понял (RM) * 2016-10-01: Улучшено с использованием специальных монад (JP) * 2016-02-03: Удалена проверка типов (LI) * 2015-03-14: Добавлено объединение с проверкой типов (JR) * / function comb ( a , b ) { return a + b ; }
Хороший:
функция comb ( a , b ) { return a + b ; }

Обычно они просто добавляют шума. Пусть имена функций и переменных вместе с правильным отступом и форматированием придают визуальную структуру вашему коду.
Плохой:
////////////////////////////////////////////////// ////////////////////////////// // Создание экземпляра модели области /////////////// ////////////////////////////////////////////////// /////////////// $ scope . model = { меню : "foo" , nav : "bar" } ; ////////////////////////////////////////////////// ////////////////////////////// // Настройка действия //////////////// ////////////////////////////////////////////////// ////////////// const actions = function ( ) { // ... } ;
Хороший:
$ scope . model = { меню : "foo" , nav : "bar" } ; const actions = function ( ) { // ... } ;
Надеюсь, эта статья была вам полезна! Я что-то упустил? Поделитесь вашим опытом!
Исследование, описанное в статье про идеальный код, подчеркивает ее значимость в современном мире. Надеюсь, что теперь ты понял что такое идеальный код и для чего все это нужно, а если не понял, или есть замечания, то не стесняйся, пиши или спрашивай в комментариях, с удовольствием отвечу. Для того чтобы глубже понять настоятельно рекомендую изучить всю информацию из категории Разработка программного обеспечения и информационных систем
Часть 1 Идеальный код на PHP и Javascript
Часть 2 1. Комментарии и Документация - Идеальный код на PHP и
Часть 3 Объекты и структуры данных - Идеальный код на PHP и
Часть 4 Тестирование - Идеальный код на PHP и Javascript
Комментарии