Сегодня на Hacker News был вопрос о том, была ли продуктивность выше в прошлом и не только ли усложняли работу инструменты, которые должны были сэкономить нам время и головную боль [sic].

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

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

  1. Система Y - это абстракция над системой X
  2. Y сложнее / сложнее, чем X
  3. Следовательно, Y плохой / бесполезный.

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

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

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

Многие программисты смеются над такими заявлениями о продажах, но те же самые кодировщики обычно все еще пропагандируют интуицию, что абстракции более высокого уровня должны быть по своей сути проще, чем те системы, которые они абстрагируют. Если C или C ++ сложны, это нормально, потому что они предполагаются сложными. Если CSS или JavaScript сложны, то это дефект, потому что они должны быть проще. Если компилятор сложный, это нормально, потому что компиляция предполагается сложной. Если система сборки сложна, то это дефект, потому что она должна делать вещи проще.

Но как возникает сложность в системе? Давайте рассмотрим эти две системы, X и Y, ранее. Представьте, что X - базовая система. Это самый низкий уровень, насколько это возможно. Система X будет иметь набор операций и концепций определенного размера. Со временем, по мере развития X, размер этого набора, вероятно, будет расти. Между тем, сложность задач, для которых его используют, также будет расти. И люди, использующие его, начнут замечать определенные шаблоны использования, которые повторяются во всех задачах.

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

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

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

В какой-то момент кто-то, вероятно, решит, что система Y стала слишком сложной. Они определят новый набор концепций и операций и создадут новую систему Z, которая абстрагируется от Y, и процесс начнется снова.

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

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

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

Оценивая любую систему, мы должны остерегаться ряда ошибок и рефлексивных суждений:

Поскольку система является абстракцией, в целом она должна быть проще, чем абстрагируемый объект.

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

Что сложная абстракция должна быть излишне сложной абстракцией.

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

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

Эта невыученная сложность хуже усвоенной сложности.

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

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

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