Элегантность решений
Когда работаешь в IT, очень легко сосредоточиться на крупных, сложных решениях. Кажется, что именно там и должны находиться хорошие решения — масштабные системы, множество программ, все новейшие гаджеты. То, чем мы занимаемся, захватывает, и очень легко поддаться этому порыву. Интересно браться за сложные, масштабные проекты. Когда слышишь, что делают другие IT-специалисты, как другие компании решают свои задачи, когда общаешься с вендорами, предлагающими большие системы — всё это подпитывает азарт, и очень легко потерять ощущение масштаба и цели. Настолько часто встречаются громоздкие, избыточные решения простых проблем, что начинает казаться, будто IT так и должен выглядеть.
Но так быть не обязано. Сложность — враг как надёжности, так и безопасности. Излишне сложные решения увеличивают стоимость как при приобретении и внедрении, так и при обслуживании, при этом они, как правило, медленнее, менее устойчивы и имеют широкую поверхность атаки, которую сложно осознать и защитить. Простые, а точнее — элегантные решения являются наилучшим подходом. Это не означает, что все решения будут простыми — совсем нет. Сложные архитектуры нередко необходимы. IT — это область, где сложности более чем достаточно. Более того, часто считается, что разработка программного обеспечения может быть самым сложным из всех видов человеческой деятельности, по крайней мере среди тех, что выполняются в сколько-нибудь значимом масштабе. Типичная IT-инфраструктура включает миллионы строк кода, сотни и тысячи протоколов, большое число взаимосвязанных систем, слои уникальных программных конфигураций, количество настроек, которое ни одна команда не в состоянии знать полностью, — и только после всего этого добавляется сложность сотен, тысяч или сотен тысяч непредсказуемых и нерациональных людей, пытающихся пользоваться этими системами, каждый по-своему. IT, без сомнения, сложен.
Важно понимать, что IT сложен и этого не избежать полностью, но при этом сосредоточиться на проектировании и построении решений, которые были бы настолько простыми, изящными... насколько возможно — элегантными. Эта идея проектирования берёт начало, по крайней мере в моём понимании, из разработки программного обеспечения, где сложный код считается ошибкой, а простой, красивый код, лёгкий для чтения и понимания, считается успешным. Одна из высших похвал, которую можно воздать программному инженеру, — это признание её кода элегантным. Как нельзя кстати здесь звучит известная цитата, приписываемая Блезу Паскалю, в честь которого названо одно из популярнейших языков программирования 1970–80-х годов (в вольном переводе с французского): «Я написал длинное письмо потому, что у меня не было времени написать короткое.»
Зачастую гораздо легче спроектировать сложное, запутанное решение, чем определить, какой простой подход был бы достаточен. Независимо от того, торопимся ли мы или не знаем, с чего начать исследование, элегантность всегда остаётся непростой задачей. Отраслевая инерция подталкивает к более трудному пути. В интересах вендоров — продавать больше оборудования: не только ради первоначальной продажи, но и потому, что они знают: чем больше оборудования, тем больше доходов от поддержки, а когда нового и сложного оборудования продаётся достаточно много, потребность в поддержке перестаёт расти линейно и начинает расти геометрически — ведь дополнительная поддержка нужна не только для самого оборудования или программного обеспечения, но и для настройки и поддержки взаимодействий систем или дополнительной кастомизации. Финансовые стимулы, питающие сложность, весьма значительны, и ими не исчерпываются интересы вендоров. IT-специалисты получают значительную гарантию занятости — или её иллюзию — управляя большими парками аппаратного и программного обеспечения, которое сложно передать другому специалисту.
Нередко сложность настолько само собой разумеется, настолько ожидаема, что процесс выбора решения начинается с принятия её как данности, без какого-либо рассмотрения возможности того, что менее сложное решение могло бы справиться, или даже оказаться превосходным — безо всякого учёта вопросов сложности и стоимости. Иногда сложность и вовсе намертво прикручена к определённым концепциям до такой степени, что мне на самом деле приходилось сталкиваться с недоверием к самой идее о том, что простое решение может превзойти сложное по цене, производительности и надёжности.
Риторика — это легко, но что же взять в качестве реального примера? Лучшие примеры, которые я вижу сегодня, в основном связаны с виртуализацией — будь то хранилище данных, облачный управляющий слой, программное обеспечение или просто сама виртуализация. Я довольно часто замечаю, что разговор, касающийся только виртуализации для одного человека, сразу же влечёт за собой представление о необходимости сетевого, общего блочного хранилища, дорогостоящего программного обеспечения для управления виртуализацией, многих избыточных узлов виртуализации и сложного программного обеспечения высокой доступности — ни одно из которых не является неотъемлемым атрибутом виртуализации, и большинство из которых редко нужны для поддержки или действительно в интересах бизнеса, для которого будут внедрены. Вместо того чтобы отталкиваться от бизнес-требований, эти концепции возникают преимущественно из технологических предубеждений. Легко указать на сложность и создать видимость решения проблемы — сложность создаёт ощущение уверенности. Разберите многие аргументы до сути, и вы услышите: «Как это может не работать, если это сложно?» Сложность создаёт иллюзию полноты, ощущение решённой проблемы, но при этом легко скрыть тот факт, что решение может быть неполным или даже нефункциональным, поскольку степень сложности затрудняет это увидеть. Наш разум с трудом принимает, что более простой подход может быть более полным и решать проблему там, где сложный не справляется, — это кажется настолько контринтуитивным.
Прекрасный пример этого — то, что мы прибегаем к обсуждению избыточности вместо надёжности. Надёжность сложно измерить, избыточность легко количественно оценить. Кирпич очень надёжен — даже единственный. Кирпичу не нужна избыточность, чтобы быть стабильным и прочным. Его конструкция проста. Можно построить несущую конструкцию из множества избыточных прутьев, которая не будет и близко такой надёжной, как один кирпич. Если говорить о надёжности — вероятности того, что конструкция не разрушится, — ясно, что кирпич является лучшим выбором по сравнению с несколькими прутьями. Но если сказать «зато нет избыточности, кирпич может сломаться, и нечему его заменить», это звучит нелепо. Однако когда мы говорим о компьютерах и компьютерных системах, мы сталкиваемся с системами, настолько сложными, что редко кто понимает, имеет ли дело с кирпичом или с прутом. Поэтому, не имея возможности оценить важную надёжность, люди сосредотачиваются на легко измеримой избыточности, которая таковой важностью не обладает. Вся система слишком сложна, но поиск простого решения, напрямую обращающегося к сути проблемы, может снизить сложность и в итоге дать нам гораздо лучший ответ.
Это прослеживается даже в RAID. Зеркальный RAID прост: один диск или набор дисков является точной копией другого набора. Всё просто. Parity RAID сложен: вычисления над переменной полосой на множестве устройств, которая должна кодироваться при записи и декодироваться при отказе устройства. Зеркальный RAID лишён этой сложности и решает проблему надёжности дисков через простые, элегантные операции копирования, которые весьма надёжны и хорошо изучены. Parity RAID излишне сложен, что делает его хрупким. Однако, поступая так и подрывая собственную способность решать ту проблему, для которой был создан, он одновременно — и лишь на основании собственной сложности — кажется более надёжным. Человеческий разум немедленно переходит к «это сложно, значит, более продвинуто, значит, более надёжно» — но ни то, ни другое умозаключение не является логичным. Сложность не говорит о большей продвинутости, а продвинутость не говорит о надёжности, но сам человеческий разум сложен и легко вводится в заблуждение.
Нет простого ответа на вопрос, как найти простоту. Знание о том, что сложность плоха по своей природе, но иногда неизбежна, учит нас быть внимательными, однако не учит, когда следует заподозрить избыточную сложность. Мы должны быть бдительны, постоянно стремясь определить, существует ли более элегантный ответ, и не принимать сложность как правильный ответ только потому, что она сложна. Нам нужно ставить под сомнение предлагаемые решения и ставить под сомнение самих себя. «Действительно ли это решение настолько простое, каким должно быть?» «Оправдана ли эта сложность?» «Требует ли это той степени сложности, которую я предполагал?»
В большинстве рекомендаций по проектированию систем, которые я даю, первый технический шаг, который я обычно предпринимаю после выяснения бизнес-задачи, которую нужно решить, — это поставить под сомнение сложность. Если сложность не удаётся обосновать, она, вероятно, излишня и активно мешает достижению той цели, ради которой была выбрана.
«Действительно ли необходимо делить эти диски на множество отдельных массивов? Если да, каково техническое обоснование для этого?»
«Действительно ли для той задачи, для которой вы предлагаете его использовать, необходимо общее хранилище?»
«Действительно ли бизнес оправдывает использование технологий распределённой высокой доступности?»
«Почему мы заменяем простую систему, которая вчера была достаточна, на значительно более сложную завтра? Что изменилось так, что небольшое улучшение при сохранении простоты уже недостаточно, а требуется на порядки большая сложность и затраты, которые ранее не были оправданы?»
Это лишь типичные примеры — сложность присутствует в каждом аспекте нашей отрасли. Ищите простоту. Стремитесь к элегантности. Не принимайте сложность, не подвергнув её тщательной проверке. Пропустите её через горнило вопросов. Не позволяйте сложности проникнуть туда, где она не оправдана. Не ошибайтесь в сторону сложности — в случае сомнения, отдавайте предпочтение простоте. Чрезмерное упрощение решения, как правило, приводит к незначительному отказу, тогда как избыточная сложность открывает возможность для куда более серьёзного отказа. Более безопасная ставка — на более простое решение. А если простое решение окажется недостаточным, добавить сложности куда проще, чем её убрать.
