Понимание стоимости

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

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

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

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

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

3 вопроса

Перед добавлением любого нового элемента в ваше программное обеспечение вы должны задать себе 3 вопроса:

  • Служит ли элемент цели?
  • Это добавляет ценность (например, повышает удобочитаемость)?
  • И какова стоимость добавления элемента?

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

Удалить личное мнение

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

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

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

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

Добавление элементов для повышения читабельности

В качестве примера соотношения достаточности и удобочитаемости рассмотрим задачу «Игра в боулинг» — классическое ката программирования, позволяющее выиграть одну линию в американском боулинге с 10 кеглями. Подумайте о фреймах, ударах, запасных частях и больных пальцах. Вот решение из 13 строк, которое принимает последовательность выводов для одной линии. Предполагается, что последовательность действительна.

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

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

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

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

В случае с игрой в боулинг мы могли бы ввести код, который лучше объясняет ключевые понятия игры: страйки, спэры, открытые фреймы:

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

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

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

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

Вывод

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

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

Первоначально опубликовано на https://www.instil.co 4 сентября 2019 г.