Использование дизайна, психологии и эмпатии для улучшения кода

Эта статья представляет собой переработанный фрагмент одноименного доклада, который я сделал на ExplodeConference в мае 2016 года в Лондоне. Слайд-колода приведена ниже. В качестве внешнего веб-разработчика контекст будет одним из javascript.



Код — это пользовательский интерфейс

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

Первый код, который мы написали, был очень «низкоуровневым». Это был машинный код. Это было на языке компьютеров. Постепенно поднимаемся выше.

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

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

Дизайн для вашей аудитории

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

Но… разве мы не люди? Мы кое-что знаем о людях, не так ли?

Люди рациональны, общительны, суперхладнокровны, и мы никогда ничего не забываем. Правильно?

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

Тем не менее, мы можем кое-что сказать о нас, не причисляя разработчиков к классическим категориям: Мы часто сталкиваемся со сложными дедлайнами. Мы находимся в отрасли, которая меняется с сумасшедшей регулярностью. Мы проводим большую часть нашего времени на незнакомой территории. Мы тратим большую часть нашего времени на более разочаровывающие части нашей работы (отладка!), потому что то, что мы можем сделать, мы просто делаем.

«Ад — это другие люди» — Джон Поль Сартр

«Ад — это чужой код» — Древняя пословица

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

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

Интуитивно понятный код

Интуитивно понятные пользовательские интерфейсы разработаны с учетом множества вещей. Есть много способов нарезать его, но основная разбивка может быть такой:

  1. Возможность обнаружения
  2. Ясность
  3. Иерархия информации
  4. Контекст
  5. Последовательность
  6. Предотвращение ошибок и восстановление

Я украл большую часть этого списка из презентации Грега Нили на Explode о том, что пользовательский интерфейс везде, и я был поражен тем, насколько применимы все эти концепции к разработке (+, возможно, ко всему).

Поэтому я хочу, чтобы вы снова прочитали этот список и мудро кивнули.

Так что в него входит множество вещей, но главная мера (да! числа!) того, является ли код интуитивно понятным, — это то, сколько времени требуется человеку, читающему его, чтобы понять. И не только строку, которую вы читаете, но и то, как одна команда относится ко всему ее контексту и окружению.

Поскольку мы по своей природе отвлекаемые существа, разрыв между видением и пониманием дает возможность бездельничать. Вот разбивка примера поиска функций (как показано в левой части очень профессионального графика выше):

  • 2м: найти функцию
  • 2 с: функция чтения
  • 8s: перечитайте функцию, более внимательно
  • 3м: отвлекись на электронную почту
  • 2 с: функция чтения
  • 20-е годы: попытайтесь понять, что он делает
  • 3м: гугл/стек переполнен!
  • 3м: отвлекся на переключение контекста

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

Итак, вот некоторые вещи, которые следует учитывать при стремлении к пригодному для использования коду.

Когнитивная нагрузка

«Мир настолько сложен, запутан и перегружен, что для того, чтобы увидеть его с какой-либо ясностью, вы должны сокращать и сокращать».

— Итало Каливино

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

Держите одну руку на стене

{⇥{⇥{⇥{⇥{⇥{ console.log(`here be dragons!`) }}}}}}

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

Поверь мне, солдат, чем дальше ты отойдёшь от стены, тем больше шансов, что тебя укусят. И это относится к SCSS, HTML и javascript или другим языкам.

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

(Циколматическая сложность)

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

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

Что еще { ?

Другие утверждения сами по себе непонятны. Они требуют чтения инициализирующего if, чтобы понять их контекст.

Вместо этого постарайтесь относиться к этому негативно с самого начала. Часто это так же просто, как короткое замыкание вашего состояния:

if (!condition) return false;
//do the rest...

Это не всегда так просто. Но посмотрите, сможете ли вы сделать это так просто. Если у вас есть серия else if, вероятно, можно разбить все на более мелкие единицы работы.

Не инкапсулируйте, инкапсулируйте - рано!

Возможно, вы слышали такие фразы, как «инкапсуляция», «атомарный дизайн», «композиция», «принцип единой ответственности».

Краткая версия: создавайте элементы (будь то классы, функции, модули) с довольно краткими описаниями работы.

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

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

Побочные эффекты могут включать…

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

  • Неизменяемость.Изменение чего-либо затрудняет понимание того, что это есть или будет. Вместо этого сделайте новую вещь.
  • Чистота: чистая функция не зависит ни от чего, что не передается ей явно, поэтому ее результат при одних и тех же входных данных будет идентичным, независимо от того, что еще произошло в системе.
  • Декларация: это означает говорить о том, что вы делаете, а не о том, как вы это делаете. Что в основном влечет за собой превращение всего в функцию и отказ от использования циклов. Поначалу это действительно странно, но использование карты вместо цикла for может сделать вас очень счастливым разработчиком (это действительно «декларативно», но помните, насколько важна согласованность [я думаю, ответ: не совсем важно]).

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

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

Сделай это так!

Если вы пишете javascript, ESlint — отличный инструмент для обеспечения соблюдения некоторых из этих правил (и еще некоторых, о которых я собираюсь упомянуть). Лично я не люблю устанавливать жесткие и быстрые правила для таких вещей, но это может быть забавным упражнением.

  • сложность: ограничивает цикломатическую сложность программы.
  • max-depth: устанавливает максимальную ⇥⇥⇥ глубину вложенности.
  • max-len: когда строки длинные, их становится трудно читать. найти причину вставить перевод строки!
  • max-nested-callbacks: вы можете определить функцию внутри обратного вызова, и вы можете определить функцию внутри этого обратного вызова, и вы можете… но, возможно, вам не следует
  • max-params: чем больше параметров должна обрабатывать функция, тем выше вероятность того, что вы упустите один из них.
  • max-statements: чем больше операторов в функции, тем больше вы устанете в конце и тем меньше вероятность, что вы сможете использовать ее повторно.

Сигнал › Шум

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

В программировании это часто связано с синтаксисом и обычно улучшает понятность кода. Часто это просто другой способ думать о «когнитивной нагрузке», т. е. любой шум — это нагрузка, но я думаю, что это стоит рассмотреть отдельно.

Вот некоторые источники шума в коде:

  • Непонятные алгоритмы
  • Точное повторение
  • Почти повторение
  • «^\(*\d{3}\)*( |-)*\d{3}( |-)*\d{4}$» (все регулярное выражение)
  • Побочные эффекты
  • UFI (неопознанные гребаные целые числа)
  • для петель/все петли?
  • Весь синтаксис?

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

Не заставляй меня повторяться

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

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

Базовой единицей различия в программировании является параметр функции, поэтому основной способ избавиться от повторений — создать функцию, которая принимает различия в качестве параметра. Чуть менее базовой единицей различия может быть класс или объект, если вы хотите относиться к вещам таким образом. (У Сэнди Метца есть довольно классное объяснение этого от RailsConf под названием «Ничто не является чем-то»).

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

Сладкие синтаксические сахарные сигналы

ES6 — отличный способ уменьшить шум в вашем коде. Больше всего мне в нем нравится простота создания модулей и классов, не беспокоясь о том, сколько (){function{})_)() нужно поместить в редактор, прежде чем вы начнете писать.

Но есть куча других мелких деталей, уменьшающих шум:

{foo: foo, bar: bar, quok: quok} //ES5
vs
{foo, bar, quok} //ES6

Традиционная конкатенация строк довольно шумная, но шаблонные литералы ES6 делают ее намного чище.

return 'There are <span class="number">'+ data.string1.numDogs + '</span> dogs attacking my ' + data.string1.target '\'s house';
vs
const {numDogs, target} = data.string1; //destructuring
return `There are <span class="number">${numDogs}</span> dogs attacking my ${target}'s house`;

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

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

Для чего все это ()?

Циклы for — довольно стандартная часть программирования, потому что именно так мы перебираем массивы. Но они шумные, особенно если они гнездятся. Вы даже можете прочитать интенсивное обсуждение лучшего способа написания цикла for в javascript.

for (var i = array.length - 1; i >= 0; i -= 1) {
  myFunction(array[i])
}
vs
array.map(myFunction)

С функционально окрашенными функциями, такими как map и reduce, вы можете сосредоточиться на единицах работы, которые необходимо выполнить, а не на том, как они синтаксически связаны.

Похороните своих демонов

Код не всегда аккуратный. Интенсивные алгоритмы — большая часть нашей работы. Но лучше отделить их от более высоких, более человеческих задач. Подумайте о создании класса или даже файла с простыми, удобочитаемыми функциями для обработки данных и необходимых вам манипуляций. Даже на простых сайтах мне нравится создавать папку сервисов со всей логикой обработки данных из внешних источников (аналитика, API и т.д.).

Уменьшите сложность там, где вы можете, и где вы не можете попытаться замести ее под ковер!

В поисках одной ясной мысли

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

Раздел без названия

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

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

  • Подсказки: num__ или __Count, если вы возвращаете число. is__, если вы возвращаете логическое значение
  • Внимательно изучите шаблоны проектирования: средство форматирования, адаптер, сервис. Будьте осторожны с ними, потому что многие сложные не особенно удобны для пользователя.
  • Уменьшить шум (компания_человек_коллекция по сравнению с персоналом)
  • Остерегайтесь расплывчатости и каламбуров: менеджер может означать разные вещи, данные бессмысленны,
  • Не бойтесь просить помощи у людей или тезаурусов
  • Склоняйтесь к легко различимым именам. У нас был калькулятор, основанный на наборе доходов и продуктов и наборе инвестиционных продуктов. Эти имена на 78% похожи, и мы продолжали их путать. А как насчет сберегательных планов и доходных продуктов?
  • НЕ называйте вещи. Именование вещей не всегда необходимо, но если этого не делать, границы между тем, что является единицей, стираются (это включает в себя отказ от использования div-оболочек в HTML, анонимных функций и длинных функций) и затрудняют разделение вещей на части.

Незапланированный раздел

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

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

Уважаемый разработчик: вы также являетесь дизайнером пользовательского интерфейса.

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

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

Вырабатывайте привычки

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

Также подумайте о том, какие препятствия могут стоять на вашем пути с психологической точки зрения. Возможно, вам мешает процесс сборки (или у вас его нет), или вас останавливает какой-то ментальный блок. Лично я обнаружил, что при использовании более надежного редактора с инструментами рефакторинга у меня больше шансов разбить код на разные функции и разные файлы, потому что я меньше беспокоюсь о неправильном названии. Я также был завален всеми способами определения модулей в javascript, и переход на ES6 помог мне не беспокоиться об этом.

выше и выше

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

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

Дальнейшее чтение/просмотр