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

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

Простой пример


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

public void populate(String name, String email) {
  Map<String, Set<String>> nameToEmails = getNamesToEmails();
  Set<String> emails = nameToEmails.get(name);
  if (emails == null) {
    emails = new HashSet<>();
    nameToEmails.put(name, emails);
  }
  emails.add(email);
}

public void populate(String name, String email) {
  SetMultimap<String, String> nameToEmails = getNamesToEmails();
  nameToEmails.put(name, email);
}

Первый фрагмент кода вообще не требует знать от вас абстракции Multimap. Вся функциональность второго примера в первом примере достигнута при помощи простого Map и ничего больше. Взгляните, как же просто! Если производительность нас не волнует, то, возможно, стоит отойти и от абстракции Map, использовав вместо неё просто примитивные массивы?

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

Открытость к абстракциям


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

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

И в этом заключается причина трений. То, что одному кажется очень простым, кому-то другому кажется переусложнённым. И оба они правы — было бы ошибкой говорить, что код универсально «прост» или «сложен». Он «прост» или «сложен» только для читающего.

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

Допустим, в вашей кодовой базе есть какой-то многократно повторяющийся «паттерн».
Алиса видит, что этот паттерн можно выделить в полноценную абстракцию. Что эту абстракцию можно перенести в собственный класс или вспомогательный метод, чтобы её можно было логически сгруппировать и лаконично вызывать из различных мест. Боб способен понять достаточно быстро и считает, что код стал намного проще. Кэрол гораздо сложнее понять эту абстракцию, и она считает новый код переусложнённым бардаком.

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

Важность выбора инструментов


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

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

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

Каков твой уровень абстракции?


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

К сожалению, это просто неправда. «Хорошесть» кода совершенно относительна. То, что «хорошо» для одного, может быть «переусложнённым уродством» для другого, и «дублированным многословным бардаком» для третьего.

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

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

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

То же самое можно сказать и о способности читать код. Некоторые программисты «читают» на уровне выпускников вузов. Они способны быстро понимать абстракции, даже многоуровневые, ценить вносимую ими краткость и логическое группирование. Они отдают преимущество таким принципам, как Don’t-Repeat-Yourself, Single-Level-of-Abstraction и Small-Functions.

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

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

Ищем баланс


Часто говорят о «правильных» и «неправильных» способах писать код, и во многих случаях это очень полезно. Некоторые абстракции обеспечивают замечательную краткость и группирование, оставаясь при этом простыми и лёгкими в понимании. Допустим, никто и не мечтает встраивать в код такие абстракции, как ArrayList, или HashMap, или Heap.

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

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

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

Здесь нам сильно поможет описанная выше аналогия с чтением. Если вы Дональд Трамп, то лучше всего общаться со своей аудиторией, разговаривая на уровне пятого класса школы. Если же вы автор, пищущий для NYTimes, то аудитории больше подойдёт, если вы будете писать на уровне десятого класса.

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

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

NYTimes не случайно пишет на уровне десятого класса, а ABC news — на гораздо более простом уровне. Ни один из источников нельзя назвать «правым» или «неправым» — оба они обслуживают свою целевую аудиторию. Стремитесь поступать так же в своём коде.



На правах рекламы


VDSina предлагает безопасные серверы на Linux или Windows — выбирайте одну из предустановленных ОС, либо устанавливайте из своего образа.