Я хочу сегодня порассуждать об окружающей нас (людей) сложности и о нашем умении с ней работать. Не о той сложности, про которую пишут в статусах семейного положения в соцсетях, типа, «всё сложно», а о сложности в организационно-технических системах (кстати, по-моему, неплохое название для ВУЗовской специальности получилось). На оригинальность и, тем более, истину не претендую (тем более что, как минимум, наполовину я тут собираюсь низводить, курощать и дуракавалять). Часть этих рассуждений я уже выносил куда-то в комментарии, но для меня этот вопрос не закрыт. Поэтому жизнь всегда подбрасывает мне разные показательные примеры, которые побуждают размышлять дальше. Несмотря на пятницу, это не задумывалось, как развлекательное чтиво, тут не будет весёлых картинок, если что – я вас предупредил. Если хотите прочитать только одно предложение, и пойти читать остальные весёлые пятничные статьи – то вот оно: «Упрощать сложность там, где это можно сделать, справляться со сложностью там, где упрощать её нельзя, и нарабатывать опыт и умение отличать первый случай от второго».
Немного цитат из великих:
Понять – значит упростить.
Упростить – значит не понять.
Простота требует проектирования и хорошего вкуса.
Делай просто, насколько возможно, но не проще этого.
Сложность и так окружает нас повсюду. Мы пользуемся сложными техническими приборами, чтим сложный уголовный кодекс, внутри нас сложная иммунная система борется с коронавирусом, самые простейшие одноклеточные живые существа несут в себе поражающие воображение сложные органеллы, простейший закон Ньютона оказывается упрощением гораздо более сложного закона при нерелятивистских скоростях, а про сложность Стандартной Модели и всяких разных квантовых механик я вообще молчу.
Сложность – это всегда определённый порядок, определённая система взаимодействующих элементов, и в полном соответствии с определением этого базового понятия, сложность растёт тогда, когда увеличивается количество элементов и когда растёт число и разнообразие связей между этими элементами. Может быть, сложность – есть синоним порядка, антитеза для хаоса?
Жизнь вообще есть самопроизвольное возрастание сложности внутри нас за счёт уменьшения сложности снаружи, как любой приличной диссипативной системе положено. Энергия при этом перераспределяется так, что для повышения сложности какую-то её часть нужно затратить, но полученная организация, полученный порядок, даёт «доступ» к большим объёмам энергии. Это и есть, я думаю, эволюционная причина «самопроизвольного» возрастания сложности жизни.
Сложные системы вокруг нас, сложность организации материи и энергии вокруг, которую хочется диссипизировать, приводят к возрастанию сложности у потребителя, и дальше по цепочке. Цветок, в котором добраться до нектара можно только с помощью длиннющего хобота, вызывает
Мы – программисты, мы создаём программные системы, которые, как тот хобот у бабочки, должны быть хитровывернуты под автоматизацию решения аналогично хитровывернутых сложных процессов в жизни.
Мы – программисты, мы создаём сложные программные системы, и кто бы там что ни говорил, нам нравится создавать эту сложность, но есть один нюанс, который отличает нас от создателей любых других сложных технических систем.
Создатель сложного материально-технического устройства ограничен прочностью, трением и прочим сопроматом, приглушающим слегка полёт его фантазии. Сила трения программиста не волнует и не ограничивает (если только он не разработчик лучшего в мире симулятора гидроразрыва пласта), прочность и вес устройства тоже, и отсюда, на мой взгляд, и вытекает главная проблема.
А она заключается в том, что нам, программистам, слишком просто создавать сложность. Слишком легко она нам даётся. Ctrl+C и Ctrl+V, новая функция, новый модуль, новая библиотека, новый слой абстракции, макросы-шмакросы, препроцессоры-постпроцессоры, адаптеры, конвертеры и фасады – это всё будет работать, стоит только подбавить побольше частоты и оперативки, и никакой понизитель трения не нужен. В тварном физическом мире всё не так просто. Где в промышленном производстве аналоги не то что генетического программирования, а хотя бы даже просто лисповских макросов?
Ещё раз. Слишком просто в программировании добавить сложность, и слишком сложно в программировании понизить сложность. К тому же тех, кто в программировании понижает сложность, никто и никогда не любит, потому что при рефакторинге они всё и всегда ломают.
Я не говорю, что сложность в коде – это плохо. Код автоматизирует реальную жизненную задачу, он её отражает в своих моделях данных, код не может быть проще, чем жизнь. Сложность кода растёт вместе со сложностью задачи, но неграмотный разработчик добавляет сильно больше сложности в код, чем прибавилось сложности в задачу.
Грамотный разработчик сдерживает себя во внесении сложности в код. Не зря великие говорили, что раз отладка сложнее написания кода, то не получится отлаживать код, который написал на пределе доступной тебе сложности. Но я бы сказал ещё, что грамотный разработчик не создаёт решения сложнее, чем на 84% от своей способности со сложностью справляться.
Невозможность спроектировать будущие непредсказуемые изменения требований жизни приводит к тому, что код приходится переписывать и перерабатывать. Здравствуйте, я ваш Кэп. Но нельзя сложные программные системы переписывать с нуля только потому, что они тебе не нравятся своей сложностью.
Сложность и запутанность – это разные вещи. Как я всегда говорю студентам, которые принесли чужую лабу и уверены, что они её поняли (недавно два кадра даже сказали, что они думали, что должны научиться объяснять чужой код, а не писать свой – объяснять, Карл, даже не править и развивать!), нельзя понять, что ты чего-то не понимаешь, если ты этого не понимаешь. Неотличима по сю сторону индуктивного порога ситуация «мне кажется, что я понял» от ситуации «я на самом деле понял».
Если кто-то приходит к тебе и говорит: «Да тут у вас слишком сложно, мы напишем с нуля» — нельзя его к написанию подпускать, надо чтобы сначала он продемонстрировал, что старую систему отрефакторить сможет. Если ты не можешь справиться с той сложностью, которая уже есть, методом постепенного рефакторинга, то когда начнёшь писать сам — наворотишь сложность запутанность ещё хуже и в итоге задачу не решишь. А всё почему? Потому что нельзя понять, что именно ты не понимаешь и недооцениваешь, по определению.
Совсем утрируя: даже изобрести правильный велосипед с первого раза не получится. Первый велосипед будет кривой-косой, с тремя попарно соединёнными шестерёнками, как на классических картинках у девочек-дизайнеров. Но он поднимет тебя до того уровня сложности, работа с которой требуется при его построении, и второй велосипед уже выйдет толковым. Свой класс строк пишут не для того, чтобы научиться синтаксису, а для того, чтобы огрести животворящую порцию сложности.
Ещё сложность одного и того же куска кода, одного и того же решения, очень сильно зависит от того, в насколько сложную уже систему он вставляется, и сложность системы не есть сумма сложностей подсистем. И это – часть проблемы при работе с заказчиком или любым другим наблюдателем со стороны. Вы наверняка много раз слышали: «Это же легко сделать, это просто {действие Х} {внутри системы Y}, вон оно ведь уже есть {внутри системыZ}!». Это результат недооценки системной сложности, когда человек считает, что если что-то несложно сделать отдельно от всего остального, значит это легко сделать и внутри уже готовой большой системы. Если в программе нужно реализовать A, B, C, D, E и F, и все они примерно одинаковые по сложности, то сильной недооценкой будет считать, что они и будут встроены за одинаковое время.
Главное для опытного программиста — умение управлять сложностью. Обычно мы сложность только добавляем (нельзя же заниматься только рефакторингом), но горе тому, кто так до рефакторинга (по сути, упрощения!) и не доходит. Тогда вместо того, чтобы наводить порядок и упрощать, такой разработчик накручивает костыли на костыли и остановиться не может, потому что костыли писать проще. Со временем костыли писать становится всё сложнее и сложнее, но фишка в том, что в каждый момент времени написать очередной костыль хоть и всё сложнее и сложнее, но всё равно всегда проще, чем расчистить конюшни и навести порядок. И всегда есть эта иллюзия, что по причине дедлайнов оптимальное решение — писать костыли. Увы, это оптимальное решение в моменте, но очень неоптимальное в долгосрочной перспективе. Жадное программирование.
Умение справляться со сложностью, предвидеть последствия и видеть взаимосвязи за пределами рассматриваемого объекта есть само по себе большая профессиональная ценность, именно этим путём программисты попадают в менеджеры и начальники. В каком-то смысле, предсказание поведения сложной системы, предвидение последствий новых возникающих системных связей, «мысленный дебаг» и «проверка на крайние случаи», «к чему это приведёт», как профессиональный скилл программистов, поощряет их рост в управленцев, наряду с общими навыками абстрагирования, индукции и дедукции. Правда, рефлексия и интроспекция интроверсия, как и ряд других профессиональных скиллов программистов, наоборот, ограничивает их в этом росте.
Как научиться управляться со сложностью? Нет у меня рецепта, кроме совета учиться видеть, что работает на это умение, а что работает против него. Но в любом случае, думаю, всё начинается с самого обычного образования. Учёбы. Повторение – мать учения. Я – преподаватель, у меня профдеформация: повторять одно и то же два раза. Я – преподаватель, у меня профдеформация: повторять одно и то же два раза. Я обучаю естественные нейронные сети
К обучению вообще и обучению в школе и университете в частности, часто много претензий по поводу того, что производится обучение чему-то неактуальному, мозги пичкаются ненужными знаниями и навыками. У моей дочки были такие полые кубики с отверстиями разной геометрии, и внутрь проваливались только меньшие фигуры соответствующей формы. Есть кто-нибудь, кто считает, что ребёнку, которого учат подбирать ключик нужной геометрической формы, понадобятся во взрослой жизни навыки медвежатника?
Я думаю, что очень серьёзная часть образования, причём прямо с нуля лет, и до защиты первой диссертации, это тренировка мозга умению справляться со сложностью. Когда ребёнок в школе учится перемножать трёхзначные числа столбиком на листке бумаги, никому в здравом уме не покажется, что этот навык ему пригодится в жизни. Правильно перемножить два трёхзначных числа в столбик – это упражнение на умение напрягать мозг, удерживать пару чисел в уме, и не терять концентрацию в течение заданного периода времени. Сначала складывать в столбик, потом умножать, потом делить. По нарастанию сложности. Умение напрягаться, умение трудиться.
Нужное ли это качество? Смотря кого вы хотите создать! Если «квалифицированного потребителя», то ненужное. Если «человека-творца», то, я считаю, нужное. В жизни не пригодится умение умножать столбиком, в жизни пригодится умение перемножить эти же числа на телефоне, если нужен точный ответ – и умение без телефона в уме оставить только 1 значащую цифру от каждого числа и прикинуть примерно порядок получаемого значения. А это, кстати, тоже есть не что иное, как умение работать со сложностью: быстро принимать решения по сложным данным, упрощая входные данные и используя приблизительные прикидки. Но если кто-то считает, что в работе ему не понадобится концентрировано и без ошибок выполнять какие-то похожие рутинные операции, то, скорее всего, он не собирается в этой жизни работать головой.
Завершая этот, безусловно, мало упорядоченный поток мыслей я хочу только ещё раз повторить вынесенный в самый первый абзац призыв. Учитесь упрощать сложность там, где это можно сделать, учитесь справляться со сложностью там, где упрощать её нельзя, и нарабатывайте опыт и умение отличать первый случай от второго.