¶ — Введение. Почему “Чистый код” — не истина в последней инстанции?
Друзья, привет! Это подкаст «Организованное программирование». Я его ведущий Кирилл Макемнин. И сегодня у меня нету гостей, потому что сегодняшний выпуск — это разбор. Разбор, который я очень давно хотел сделать. Сегодня мы разбираем книжку «Чистый код». Прям открываю текст, смотрим вещи, которые там писал Мартин, и я говорю свое мнение на эту тему. Потому что периодически это возникает, периодически спрашивают, люди продолжают по ней учиться, продолжают...
следовать, пытаться следовать тому, что там есть. В принципе, я свое мнение много раз обозначал. Понятное дело, что в любом месте есть какие-то вещи, которые выглядят разумно, хорошо и все такое. Но для меня книжка Мартина воспринимается скорее все равно как... Очень такая несистемная штука, потому что она просто говорит, вот смотрите, вот если так выглядит вот так, если так выглядит, то можно вот так сделать, не ставя за рамками этого какие-то фундаментальные принципы.
или, кстати, даже местами не так их воспроизводят. Я вам покажу несколько примеров, что приводит к тому, что человек как бы наполняется, ему кажется, смыслами у него много в голове возникает. паттернов, подходов того, как что-то надо делать. При этом из-за того, что нету базы какой-то, это все равно все не приводит к реально хорошему коду и пониманию того, что такое хороший код и что такое нехороший код.
Опять же, речь не идет о том, что те вещи, которые он описывает, они там все плохие, далеко не так. Просто это чаще всего следствие каких-то других вещей, которые лучше один раз выучить, понять и запомнить, и дальше применять везде. Плюс, конечно же, есть специфика, связанная с самим языком. Потому что Мартин, во-первых, он писал это все давно. Когда он это писал, это очень сильно было завязано и до сих пор завязано на джаву и джаву-подобные языки.
Поэтому большое количество принципов, которые здесь описаны, они вообще-то людям на других языках, ну, совсем никак не помогают. И что самое интересное, все-таки Мартин с тех пор... Сам много чего попробовал и много во что окунулся. Например, с тех пор он там Руби попробовал, Кложу попробовал. И вообще, если почитать, посмотреть, изменил мнение на многие вещи. Начал говорить, о, а вот это вот так, вот это вот так. Плюс, конечно же, кто следит за его блогом или за его...
Твиттером знает, сколько ему в Панамку пихают, и всякие другие ребята разборы делают, и свое отношение к этому. Опять же, здесь это все очень странно, потому что... он не является каким-то супер-мега признанным экспертом в плане техническом, потому что человек вообще на себя сам идет там, работает, какие-то штуки делает. То есть он в этом плане дальше от промышленного программирования, чем многие из нас, да, кто этим занимается.
И при этом о нем чаще всего говорят, больше всего. Вот он как-то такую славу заслужил, получил, и, собственно, вот мы поэтому все это добро разбираем. То есть, грубо говоря, если бы про эту книжку не особо говорили, я бы, наверное, особо на нее внимания не обращал. Но поскольку про нее говорят...
¶ — Почему разбирать эту книгу всё ещё актуально?
Постоянно ставят в пример, поговорить про это невозможно. Вот, так что... Я ни в коем случае не хитер Мартина, но из-за того, что все это рождает очень много заблуждений, нужно, конечно, это разбирать. Кстати, был такой бум лет пять назад, при том, что книжка намного раньше написана, был бум пять лет назад, все делали такие видосы, но вот... Я их немножко посмотрел на днях и вот решил тоже в этом добре поучаствовать. При этом там очень много разбирают начальных глав и очень мало разбирают...
то, что идет в конце. Поэтому я попробую сделать по-другому. Я начну сразу с функций, то, где уже есть какие-то интересные моменты. И постараюсь дойти там почти до конца. Мы не затронем тему либо какие-то суперспецифические темы для Java, либо, например, многопоточность, потому что это не тема кода с точки зрения абстракции. Это такая более техническая тема.
на тему того, как писать, не писать многопоточный код. Поэтому она не касается того, что мы обсуждаем, то, что мы называем чистым кодом. Ну что, поехали. Я открываю, показываю вам на экране, что происходит. Мне кажется, что как будто этот выпуск можно слушать, если... У вас не получается его смотреть, его можно даже будет слушать. Но посмотрим, как получится. Будет интересно попробовать и такой тип разборов. Если, кстати, он зайдет, я буду регулярно такие вещи делать, потому что книжек много.
Есть что почитать, есть что пообсуждать. Да и не только книжки, статьи, в конце концов, тоже. Итак, вот оно у меня открыто. Давайте посмотрим. Значит, глава функции, 55-я страничка. Поехали. 55, 55. Вот. Функции. Опять же, я не буду читать все подряд. Буду выбирать только те вещи, которые наиболее интересны. Или там, где есть о чем поговорить, поспорить. То есть, если я что-то пропускаю, либо я с этим согласен...
либо просто... Мне кажется, это неинтересно здесь разбирать, но не факт, что я с этим согласен. Поэтому никогда заранее, что называется, не узнаете. И да, ещё я, конечно, не буду разбирать прям сами примеры кода глубоко, потому что, во-первых, тут листинги, ну, не на один экран. Плюс это джа... в том плане, что не все здесь Java знают. Плюс они еще и будут без подсветки. И читать просто код с экрана такой себе. Поэтому эту часть я в основном пропущу. Может быть, где-то будем смотреть код, но...
Если... Честно говоря, вообще, если код разбирать, который он здесь пишет, вопросиков возникает много. Потому что вообще, когда мы говорим про чистый код, тоже надо вот про это сказать. Примеры, которые любят приводить, они, конечно, довольно трэшовые. То есть... Это редко вообще имеет отношение к какому-то реальному прикладному программированию. То есть либо это уточки, кошечки, то, что вообще никуда, и такого просто не бывает.
¶ — Почему код из книги далёк от реальности?
либо ощущение, что как будто мы пишем в библиотеке. То есть примеры кода вот с прикладным кодом на фреймворках типовых, если мы опять же говорим про веб-разработку, фронтенд, бэкэнд, то... Там нет таких вещей, почти не бывает. Там по-другому бывает. Ну, например, там сервис работы с каким-нибудь эквайрингом, что-нибудь по платежам. Здесь же он такие показывает вещи, которые больше относятся к немножко другим системам или к...
тому, что обычно используется в библиотечном коде. Тут хочу сказать, что это сильно разные вещи. И глядя на дно, не то чтобы очевидно, как писать другое. То есть люди, которые умеют писать в библиотеке и разбираются в этом, это не те же самые люди, которые умеют... просто пишут прикладный код. Так что иногда, даже если он какой-то логичный пример приводит...
или какую-то тему объясняет. Думаю, сложно это довольно применить к нашему прикладному коду, если не понимать всю картину целиком. Вот. Именно из-за того, что это более такие специфические примеры, которые в реальной жизни веб-разработчиков, ну, вряд ли встретятся. По крайней мере, в таком виде. Так, ну что, давайте попробуем, пойдем дальше. Здесь он рассказывает какие-то вещи, связанные там с тем, как про что-то, про уровни абстракции, проименования, еще всякие вещи. Ладно, это мы пропускаем.
Давайте про компактность. Первое правило, функции должны быть компактными, второе функции должны быть еще компактнее. Он говорит, что я не могу обосновать, но, в общем, я писал всякое разное. Я, в смысле, он, потому что я читаю книжку. И рассказывает о том, что... Сейчас нужно функции делать максимально короткими. Причем, кстати, он еще такую интересную штуку рассказывает, что вот когда у нас было процедурное программирование,
то был такой подход, когда нужно писать все с одной точкой выхода, там, что один return должен быть. Это все, честно говоря, в современном мире не очень актуально, потому что GoTo никто не использует. Плюс, если делать единый выход из функции... она достаточно большая, там возникает проблема такого плана. То, что, допустим, вы сделали нужное вычисление, которое, в принципе, все, уже дальнейший код весь не имеет значения.
то если вы в этот момент не выходите, вам нужно дальнейший весь код писать с учетом вот этого кейса, который, в принципе, уже вычислен. И значит, его не нужно вычислять. В конечном итоге подход с одним возвратом приводит к тому, что вам на протяжении всего кода функции придется в каждом моменте думать про все кейсы, даже если эти кейсы могли быть уже завершены.
И в реальности это только делает код сложнее. То есть сделать функцию проще с одним выходом, чем функцию с несколькими выходами, невозможно. Просто потому что функция с несколькими выходами в более простых кейсах...
убирает их из вашей головы. То есть return — это не просто return функция. Это значит, что вы в дальнейшем ходе просто можете об этом не думать. Иначе вам придётся об этом думать. Поэтому появляются всякие дополнительные переменные, дополнительные данные нужно хранить, дополнительные проверки делать. Короче, это всегда хуже. Поэтому... Подход с гардами в этом смысле намного лучше. То есть если вы вначале разбираете...
какие-то кейсы, которые как можно быстрее можно определить, вычислить и завершить. И делайте return. Ого, ниже вы понимаете, что всё, минус один. Возможно, сценарий уже легче. И так дальше до тех пор, пока вы не останетесь в сценарии, где вот он самый сложный, самый глубокий, самый... продвинутый это вот общее такой момент
Теперь, значит, по поводу количества срок. Четыре строчки, все дела. Значит, об этом тоже сломано миллион копий. Я специально смотрел, что сейчас говорят зарубежные блогеры и всякие разные специалисты на эту тему. Даже, кстати, знаете, я даже хотел, честно говоря, разбор их разбора делать, потому что...
Там есть ребята довольно известные, которые собрались и такие, ну что, давайте обсудим Мартина, что там, куда, с чем мы согласны, чем нет. И это было буквально недавно. Я не помню его имя, это такой известный чувак, которого сейчас вот очень сильно...
На P как-то он, да? Вот я знаю, что меня сразу в комментариях накинут. Я его имя просто никогда вслух не произносил, поэтому не запомнил, как он произносится. В общем, идея очень простая. Чем больше, тем меньше функций, тем больше их. Вы в какой-то момент... С одной стороны, разбивая на более мелкие функции, вообще в целом вынося какую-то логику, которая по смыслу должна быть вынесена и спрятана, чтобы об этом не думать. С одной стороны, мы улучшаем.
Понимание. Но, честно говоря, там довольно быстро наступает такой момент, когда разбиение на функции, какой бы вы читаемый не делали, какие бы классные вы аргументы не писали, приводит к тому, что вам приходится слишком много прыгать, чтобы собрать всю картинку целиком, и вам становится...
гораздо сложнее. Это классическая история, связанная с распределением. То есть чем больше вы распределяете, тем больше появляется сложности с тем, что все это синхронизировали. В данном случае в голове. Очень часто бывает, что гораздо проще написать одну нормальную функцию, там, строчек на 100. И при этом просто внутри функции у вас есть независимые блоки, которые каким-то образом работают. Потому что рефакторить такой код, как правило, оказывается гораздо легче.
Конечно же, тут возникает миллиард всяких условий, принципов того вообще, где мы работаем с чем, какие языки, как мы работаем с побочными эффектами и так далее. То есть, конечно, тут можно и все, что я сказал, опровергнуть и привести контрпримеры и доказать, что я не прав.
¶ — Функции на 100 строк: это провал или здравый смысл?
Но в любом случае опыт индустриальный показывает, что функции могут быть очень большие. И намного важнее даже скорее не размер их, а то, как действительно это связано с выполняемой задачей. То есть насколько это один уровень абстракции внутри. Ну просто банально есть функции, которые делают какие-то вещи, которые...
ну, вычислительно, может быть, большие, но при этом мало затрагивают внешних систем или вообще чисто внутренняя логика. И в таком случае не так важно, на самом деле, какого она размера, потому что ни на что особо не влияет, и ваш контекст не размазывается, и вы, например, не взаимодействованы с такими системами. А бывает такое, что... Функция суперкороткая, но там сразу везде участвует. Или там слишком много разного состояния меняет соседнего. Ну, конечно, совершенно другая ситуация. Поэтому...
Наверное, хочется предостеречь от чего? Не считать догмой, что функции должны быть суперкороткие. Так или иначе, большинство людей, которые пытались прям строго-слепо следовать вот этому подходу, когда функция там чуть ли не пару строчек... Все кейсы, которые я знаю, все знакомые, которые так делали, все люди, которые об этом писали, говорили, что, блин, в какой-то момент становится слишком сложно, и у тебя просто теряется за деревьями лес, и вообще непонятно, что происходит.
У меня, наверное, такой вот пример в этом плане. Во фронтенде классно об этом говорить. Вот, казалось бы, компонент, да, это функция в том же самом реакции. И он может быть, ну, допустим, там, 500 строк. Плохо это или нет? Да вообще неплохо, потому что у вас там просто, грубо говоря, дом-дерево формируется, кусок HTML, если очень прощенно. Его вообще не надо выносить.
Если это всех устраивает, если этот компонент только так используется. Вот если внутри него появляются части, которые, например, мы хотим независимо как-то использовать, или они там внутри еще повторяются, или в других компонентах повторяются, тогда мы их выносим. Но на уровень сложности это редко влияет. Он, кстати, тут еще приводил пример по поводу навигации. Где-то там писал. Но с навигацией сейчас особых проблем нет, потому что в любом редакторе все абсолютно классно.
Подсвечиваются всякие идентификаторы LSP-шные, переходы. В общем, красота. Так что тут особых проблем нет. Короче, размер функции не принципиален. Принципиально абстракция, которую вы выделяете. И если... Оно внутри, ну, достаточно изолировано само по себе. В принципе, оно даже может быть внутри довольно грязно быть. Ничего страшного. Главное, что вот мы правильно выделили. Но здесь единственное, что хочется сказать еще. Выделение функций...
Я об этом даже в докладах рассказывал. Это все-таки в первую очередь не про повторное использование кода, а в первую очередь про смысловую абстракцию. Почему это важно, почему это не одно и то же? Потому что редактор, например, кода...
Он может вообще-то вам свинью подкладывать. Он, например, видит какой-то кусок кода, который используется повторно. И он может предложить вам сказать, о, давайте вот выделим эту функцию, смотрите, она так используется. Но с точки зрения смысла это не является функцией. То есть у вас, грубо говоря, получится, что...
¶ — “Одна ответственность” — самая расплывчатая догма в мире ООП
в рамках одной функции соединены совершенно разные вещи, которые к ней не имеют отношения. Получается, что вы как бы функцию вроде сделали, но по факту это реально вынесен просто некий блок кода, хотя на самом деле сам по себе он не является смысловым.
Поэтому функция это почти всегда про определение того, какую проблему и задачу мы решаем. Я причем боюсь говорить слова из серии «Одна ответственность», потому что мне очень не нравится эта формулировка. Почему? Потому что она создает впечатление «хорошо делаем». хорошо будет и как будто мы все понимаем о чем идет речь опять же опыт показывает когда вы берете разных программистов сажаете рядом
Ну, в смысле, наоборот, они друг друга не видят. Вы, видать, даете одну и ту же задачу и говорите, вот, пожалуйста, мне реализуй. И они такие, да, начитались солида, начитались, значит, других каких-то подходов и говорят, вот, мол, одна причина, там много формулировок, одна причина изменения, одна ответственность. делает одно. А потом, когда начинаешь смотреть, всегда это очень...
ситуативная штука, которая зависит от контекста. То есть, например, что мы считаем одной задачей. У вас класс вообще может быть целым приложением, и это во многих фреймворках так сделано. Это одна ответственность, а внутри у вас там дофига чего происходит. Или, например, вот берем какой-нибудь отчет.
Например, функция, которая генерит отчет. Одна ответственность. А если внутри это гигантская сложная система, когда вам надо, например, там хитрым образом генерировать ячейки, там еще что-нибудь в этом духе, форматы разные, это одна ответственность или нет? И что бы вы ни говорили, как бы вы ни придумывали, ни казалось, что ой, я тут все понял, вот так система раскладывается, мы берем второго программиста, говорим ему ту же самую задачу, у него будет совершенно другой расклад.
За исключением тех случаев, когда у них был опыт создания таких систем. Потому что, как правило, те люди, которые в какой-то теме понотарели, у них уже начинает что-то получаться. Я про это еще чуть позже скажу. Так, поехали дальше. Блоки отступают. Мне интересно.
Правила одной операции, да. Совершенно очевидно, что функция выполняет множество операций. Зовет буферы, производит выборку данных, ищет у нас следователь страницы. Но это он показывает пример той функции, что типа она делает все подряд. Функция должна выполнять только одну операцию, она должна выполнять ее хорошо, ничего другого она делать не должна. Вот это для меня, оно звучит красиво.
Но оно ничего не означает по факту. Потому что в любом случае, вот, допустим, там, репорт тот же самый, я говорю, у вас все равно будет функция, которая в конечном итоге, которая генерит отчет. А внутри, даже если вы там все это поразбивали на мелкие функции, будет куча совершенно разных действий. И тогда...
Получается, опять мы это можем выносить это в разные функции, а можем не выносить. С точки зрения функции, которая генерит отчет, это некая единая штука. А то, что там по пути еще надо сходить в базу, сделать разных кучу вещей, ну, это вторично.
Потом, конечно, может возникнуть вопрос, окей, а если там за данными надо в базу ходить, ну давайте вынесем эту логику. Можем. Но чрезмерное увлечение изоляцией побочных эффектов и абстракций тоже несет за собой проблемы, потому что в таком случае вы получите код...
¶ — Кто пишет лучшие библиотеки?
в котором слишком-слишком много абстракций. То есть это вот такая типичная история в Java, когда вы смотрите, и у вас там просто вот так вот друг в друга как матрёшка собирается перед тем, как что-то получается. То есть вместо того, чтобы выполнить простую операцию, у вас там нагромождено просто этих фабрик, абстрактных фабрик и так далее. Причём, кстати,
здесь это тоже будет как пример приводиться, и об этом мы чуть дальше поговорим. Вот. Поэтому вот какой важный момент я еще хотел сказать. Если посмотреть на реальную практику создания приложений, и причем, когда мы говорим не приклады приложения, а вот библиотечного кода, да.
Можем ли мы сказать, что вот прочитав вот эту книгу, другие какие-то книги, люди, которые идут создавать свои собственные библиотеки, у них, значит, они такие, о, теперь я делаю правильно. Смотрите, я правильно по функциям разбил, я правильно все понял. Ответ вообще так не работает. Если вы посмотрите на... развитие библиотек, особенно их мажорных версий, любых, вообще в любых языках, то все, как правило, зависит от...
опыта, который получили разработчики ее разрабатываемой в процессе и поняли, какие ошибки они допустили и как люди это используют и какие ограничения и сложности возникают при том интерфейсе, который они создали или тех возможностях, которые есть в этой библиотечке. И только после этого они понимают, ага, мы значит ошиблись в дизайне этой системы.
этой библиотеки, давайте ее менять, и выпускают, допустим, новую версию, в которой они, как правило, она обратно несовместимая, в которой они делают значительные изменения, расширения, тра-та-та-та-та, и внутри там все переписывают. И это касается часто и самих фреймворков, это касается библиотек.
Ну и в целом вот таких вот вещей. И помог ли им совет Мартина, например, что они такие, ну вот мы с первой версии сделали все правильно. Да вообще нет, потому что там перераспределение просто даже по...
¶ — Почему никакие принципы не заменят здравого смысла
модулем, которые там будут, оно просто другое, потому что обычно идет переосознание полностью всего этого добра. Поэтому, с одной стороны, мы не можем сделать сразу хорошо в любом случае, пока у нас нет соответствующего опыта. И поэтому, кстати, более сильные те, кто делает что-то не первый раз. То есть если я, например, специализируюсь на создании, не знаю, CRM-ок, или если мы говорим про приколовной код, или про библиотечки на создании, не знаю, front-end фреймворков, то...
У меня будет получаться в какой-то момент довольно неплохо, да, даже с первого раза. А если нет, то будет херня, какую бы книжку я ни прочитал. Есть, конечно, некоторые принципы, которые позволяют что-то сделать лучше, но по большому счету... Нужно успокоиться и плыть по течению, потому что никто еще с первого раза даже с самым классным экспириенсом не сделал так.
не работают. К счастью или к сожалению, скорее это просто помогает немножко успокоиться, просто больше рефлексировать на тему того, что окей, мы запустили, посмотрели, изменили, улучшили и так далее. Но не все изменения имеет смысл делать. СМЭ переход с питона 2 на питон 3. Окей, поехали дальше. Ну, дальше, в принципе, можно все пропускать. Это там он растекается по идее одного уровня абстракции. И да, один уровень абстракции имеет смысл.
чуть-чуть подробней. Действительно, есть концепция того, что когда мы работаем, вот, например, мы функцию открываем, какой-то кусок кода, и там есть определенные строчки, да, с которыми мы работаем, то, конечно, в идеале... желательно чтобы действительно это был один уровень абстракции но это не всегда очевидно
о чем вообще идет речь. Потому что, например, в одном месте мы читаем из базы, а тут работаем с файлом, а тут работаем с моделями. И вот, типа, например, одновременно работа с файлом и работа с моделями моей предметной области является это одним уровнем абстракции или нет? Кто-то скажет, что да, точно, это не...
ни один уровень абстракции там и так далее. Но даже если вы спрячете это за какую-то функцию, работа с файлом там никуда не денется. И учитывая, что это все-таки побочный эффект, это, честно говоря, такое как бы иллюзия изоляции. В реальности это не совсем изоляция. Наверное...
Один из ярких примеров нарушения уровня абстракции, он заключается вот в чем. Те люди, которые, а я подозреваю, что все-таки большинство так или иначе, кто смотрит, они с этим сталкивались. Это если мы берем классический бэкэнд, какой-нибудь фреймворк, и, допустим, у вас есть URM-ка.
И вы работаете с моделями, да, вот у вас есть модельки, и вы, соответственно, не знаю, там, какие-то делаете выборки, ну, даже не выборки, я скажу, выбрали модель, используя стандартные механизмы вашего фреймворка, и дальше выполняете какую-то логику с ними.
И вот если на этом уровне, на котором вы это делаете, а это, скорее всего, кстати, сервис, то есть такие вещи еще в сервисе делаются. Вот если вы на этом уровне вот работали с моделями, работали, работали, а потом херак, делаете просто сырой запрос в базу, вот это явно не тот уровень абстракции, с которым надо работать. И...
Это точно надо выделять, и тут вообще дело не в размере функции, не в размере кода, запроса и всего остального. Здесь просто проблема здесь вот в чем. Если вы начинаете писать такой код...
¶ — Копипаста как проклятие командной разработки
то в одном месте, как бы, если он появился, ну, жить с этим точно можно, и как-то дальше менять это тоже можно. Но он создает неприятную ситуацию. То есть он показывает другим разработчикам, особенно более молодым, незрелым, новеньким. что это нормально. Они смотрят на этот код такие, ну так... ну так пишут. Они могут даже не отрефлексировать, что здесь вообще какое-то нарушение уровня абстракции. Они просто видят, что вот это код вот, который у нас есть.
Почему это приводит? Это приводит к тому, что они потом этот код будут копировать. Они будут в других местах продолжать так делать, потому что, ну, мы же так уже делали, а никто нам не объяснял, что это оказывается разным уровнем абстракции. То есть это еще надо догадаться. Вот, поэтому такие вещи лучше писать правильно сразу с первого раза и думать вообще об этом, если вы понимаете, что...
Не вы единственное владеете этим кодом, и вы контролируете все, что надо. Потому что если я пишу один, я могу сказать, окей, я это сделал, потому что я могу сделать это быстро. А второй раз, когда мне это понадобится, или я доберусь до этого куска кода, я сделаю рефакторинг. Это работает только в том случае, если вы единственно над кодом работаете, и тогда вы можете...
любой шаг продумывать наперед и не бояться сделать какой-то косяк, с которым вы потом сами исправитесь, потому что вы знаете, как вы будете работать. Если вы работаете в команде, это никогда не работает. Всегда работает копипаста, и только долг этот растет. Так, чтение кода сверху вниз, правило понижения. Я читал, читал, читал, и вот прям совсем, что он хотел сказать, не до конца понял.
Вот. Поэтому я, наверное, это пропущу. Я, честно говоря, не вижу в этом ничего. То есть понятно, что он пытается сказать, как надо подряд выстраивать функции по уровню абстракции. Но вообще говоря... У вас обычно функция разбросана сильно везде по разным местам. И вообще то, с чем вы работаете, поэтому оно не в одном месте расположено. Поэтому, честно говоря, выглядит как-то немножко странно. Ну вот. Если речь идет про то, что в рамках класса ты это делаешь, ну...
¶ — Switch — враг чистого кода? Или просто инструмент?
Это не что-то такое принципиальное. Так, дальше. Написать компактную команду Switch довольно сложно. Даже команды вместе, да, больше места, та-та-та. Это... Немножко манипуляция, потому что он сам себе придумал проблему и сам себе на нее отвечает. То есть он такой сказал, функции должны быть короткими. И потом говорит, так, Switch не укладывается в эту концепцию. Поэтому относиться к этому надо с долей определенной скепсиса.
Вот. И когда он пишет, к сожалению, обойти без канала Switch не удается не всегда. Никакому сожалению. Просто если у вас есть задача свитчиться, это абсолютно нормальная задача. Примерно с таким же успехом можно было говорить. Что, к сожалению, обойтись без ифа удается не всегда. Ну, come on. Это просто нормальная часть программирования, что у вас так все это устроено. Дальше он показывает функцию, которая вообще ничего кроме свитча нет.
И объясняет там какие-то всякие недостатки. Типа, во-первых, она велика. Ну, здрасте. Показали функцию, в которой только один свитч. Я уже говорил, что отношение к этому все-таки, слава богу, сейчас более-менее здравое. сообществе разработчиков о том, что не надо так упороться по размеру функции. И это ни к чему хорошему не приводит.
Вот, а при добавлении новых типов работников она будет разрастаться. Короче, здесь он на самом деле приводит к идее того, что, ребята, у нас тут, мол, смотрите, стратегия. Давайте сделаем общий интерфейс. Давайте, значит, заменим это на, по сути, полиморфное поведение. И тогда вот этого вообще все не будет. Это нормальная история. И такое...
Встречается, бывает, когда вам это нужно. Но вообще-то не всегда нужно стараться абсолютно все решать в полиморфном поведении. Ну, то есть, когда у нас просто подменяется тип. И мы не кейсами делаем, а у вас фактически логика зашита в какую-то имплементацию, в какой-то, допустим, класс. Если вы пишете на классовом языке, но это не обязательно, кстати, так. Может, и без классов то же самое быть сделано.
И в таком случае, да, у вас как будто свитча не будет. Но это очень особый случай использования свитча, когда конкретно мы вызываем логику в зависимости такой, ближе к типу она привязана. Не всегда, но ближе к типу. У него даже здесь в примере как раз тип. Фактически, это немножко другое. Это как раз стоило, наверное, показывать...
пример в разделе, который называется не то, что свитч плохой, а что конкретно диспетчеризация по типу свитч, и это вы типа ручками реализуете ООП, да, потому что ООП подразумевает использование полиморфизма. Хотя на самом деле... Даже те, кто пишет ВВП в таких языках, они... Многие понимают, что не надо в каждое место пихать полиморфизм, свитчи иногда хорошо и нормально. Но иначе задолбайтесь. У вас количество интерфейсов и всяких таких штук будет бесконечно много.
Не все должно быть конфигурируемо на 100% и сдаваться через контейнер какой-нибудь. Просто потому что любое абстрагирование... Любая попытка обобщить код, честно говоря, делает его сложнее. То есть сначала кажется все классно, весело, здорово, но в какой-то момент, если у вас весь код такой, то в количестве абстракций и сложностей вы просто потеряетесь. Вот. Он тут еще пишет...
Во-вторых, она совершенно очевидно выполняет более одной операции. В-третьих, она в принципе не ответственности. Ой. Просто функция, которая просто делает диспатч. Вот. И ничего она не нарушает. Ну ладно, я не буду с ним здесь спорить. Короче, он тут и все грехи, какие только можно, притянул. Ну, в основном свои, которые он определяет как-то.
Вот. Ну, нет, один все-таки сказал. В-четвертых, он нарушает принцип открытости-закрытости, потому что код функции должен меняться при каждом добавлении новых типов.
¶ — Принцип открытости/закрытости: красивый, но опасный
Да, это абсолютная правда, что если вы не используете пальморфное поведение, при котором вы можете где-то задать конфигурацию, у вас по всему коду будет использоваться, то действительно это так. Но он, опять же, исходит из того, что он...
Он сам это описал, сам сказал, что это важно, сам сказал, что без этого жить нельзя, и типа давайте так делать, это фундаментальный принцип программирования. Нет, принцип открытости и закрытости не фундаментальный принцип программирования. Если у вас вся программа построена так, что она меняется только...
за счет конфигурации, это означает, что она у вас невероятно сложна. И внутри невероятно много всякого абстрактного кода. Это надо делать только тогда, когда у вас действительно есть такая потребность. Причем, кстати, чаще всего это делается реально в инструментах.
То есть в либах, в каких-то штуках, которые можно конфигурить, но, например, не в прикладном коде. То есть фреймворк, да, он часто такой внутри, там все можно так подменить. Там редко бывают подобные кейсы. Собственно, там все завязано на абстракции. А когда вы пишете конкретный преклонный код, ну, например, у вас есть там модель юзер, вы просто...
тупо инстанцируете этот модель и работаете с ней напрямую. Вы даже через контейнер не проводите. Это касается не только моделей, это может касаться и любых инфраструктурных или там дополнительно каких-то штук, которые у вас есть в коде. Вот. Поэтому... Принцип понятный. Это все четко важно понимать. То есть здесь у меня вообще никаких вопросов нет. Классно, когда вы осознаете свечи, связь с полиморфизмом, с ифами и с...
подмена имплементации с динамическим расширением поведения за счет того, что не надо переписывать код, но при этом без догматики, да, что вы понимаете, где вы это используете, где это не используете. А вот если вы...
этого не понимаете до конца, то тогда, конечно, возникает догматика, смотрите, а, вот он это написал, наверное, так правильно, да. Но все в конечном итоге сводится к пониманию полиморфизма и тому, как он работает. Конкретно речь в данном случае про сабтайпинг, то есть полиморфизм подтипов.
Не путать с параметрическим полиморфизмом. Ну, дальше он говорит, что мол, давайте абстрактную фабрику пилить. Не надо пилить абстрактную фабрику. На каждую штуку. Ну да, и он дальше немножко про полиморфный объект говорит. И еще что-то в этом духе. Кстати, здесь он еще одну вещь упоминает. Я не буду на ней глубоко и широко останавливаться. Она называется... Он, кстати, очень часто, забавно, он не говорит какой-то...
понятийный аппарат, который известен людям, который описан и который знают, он начинает это какими-то своими словами, либо немножко не то дает. То есть, когда он описывает, что В одном случае, то есть если у вас свитч или типы, в одном случае проще добавлять поведение, в другом случае проще добавлять новые типы.
Вообще-то эта штука имеет название. Это называется expression problem. Если вы с этим никогда не сталкивались, почитайте разок. Это очень полезно как раз вот в тему замены свитча полиморфизмом. Там действительно есть такой прикол, что если вы распихиваете логику по типам, вам проще...
¶ — Expression Problem: типы против поведения
добавлять новый тип динамически все такое но сложнее добавлять операцию потому что надо добавить типа во все места во все типы да то есть вам проще добавить новый тип а новое поведение которые свечом в одном месте формируются. Вам, типа, проще добавить в один свитч. Но это при условии, конечно, не используется в 50 разных местах. Я сейчас вот сказал, подумал, может быть...
Я слишком абстрактно звучу, потому что когда я про это говорю, в моей голове выглядит все очень логично, я прям вижу код. Но вполне возможно, что не у всех прям во время прослушивания возникают эти картинки. Вы, кстати, напишите про это, тоже интересно, потому что вполне возможно, когда...
в момент прослушивания таких видео, вы скажете, блин, Кирилл, сорян, вообще не выпиваем за тобой, потому что я тут мою посуду или что-то еще делаю, и слишком все это звучит непонятно, просто потому что я перед собой не вижу кода. Мне просто на будущее, чтобы я понимал, стоит ли так глубоко копать или можно как-то по-другому это подавать. Всё, поехали дальше. Используйте содержательные имена. Ну, окей, согласен.
Аргументы функции. В идеальном случае количество аргументов функции равно нулю. Абсолютная хрень вообще не так. То, что он говорит, это вообще кошмар. Это, по сути, либо о использовании глобального состояния, либо неявного состояния, что у вас все скрыто, у вас все, видимо, опять же, из-за того, что он в Java пишет, все в объектах.
И у вас, значит, все там стоит, запрятан в объекте, выполняются, значит, все операции. Любой функциональщик вам скажет, что это вообще противоречит нормальному здравому смыслу, потому что, наоборот, весь стей должен быть явный и передаваться через аргументы, через параметры функций. И...
Речь не идет о том, что они должны быть ужасных, должно быть много и так далее, а речь идет о том, что у вас должно быть явное состояние. Конечно, баланс где-то посередине, потому что, ну, все-таки, если мы пишем в Java, как ни крутите, у нас есть объекты и...
Мы с этим как бы живем. Но при этом пытаться полностью весь стейт пихать внутрь куда-то и работать только через функции, которые вообще не принимают никаких параметров, ну, ничего хорошего из этого не получится. Вот, сразу могу сказать. Поэтому... Всегда вопрос в смыслах. Вопрос не в количестве аргументов, параметров, которые принимает функция, а вопрос в том, какую проблему вы решаете и как это вписывается в вашу архитектуру. Кстати, я, например, не пишу мобилки, но когда кот видел андроида...
И пытался что-то делать. Я помню, как меня поразило, что там многие функции принимают прям реально по 10 аргументов. Причем, когда ты их туда передаешь, тебе сначала там налов надо 10, ну, в смысле, 5, например, там, передать в каком-то порядке, чтобы дойти до тех смыслов, которые тебе нужны.
Вот это выглядит перебором. И опять же, кстати, это же спроектировано людьми, которые там Android делают и так далее. То есть серьезные ребята, которые читают серьезные книжки, работают в серьезной компании Google. И в этом смысле, как минимум, им бы помог какой-нибудь именованные аргументы, да, и хотя бы так можно было на лоне передавать. Но, возможно, это решает следствие, а не причину, потому что сама причина в том, что аргументов слишком много. Тут не скажу. В реально ходе...
Прикладных приложений я редко видел, чтобы вот настолько сильно злоупотребляли параметрами. Вот мобилки только, наверное, я так видел. И то на уровне стандартных библиотек и фреймворков, а не прикладного кода.
Верю, что кто-то где-то такое пишет, но не думаю, честно говоря, что это прям такая самая большая проблема. Потому что все равно аргументы функции, честно говоря, это следствие того, как люди проектируют. То есть... Таким образом просто можно все что угодно придумать, еще 500 принципов вывести, но в реальности мы говорим о том, как человек проектирует свою систему и выделяет абстракции, и работает с тем, что там внутри.
Вот, окей, мотаем дальше. Вот, аргументы, флаги уродливы. Передача логического значения функции в астину ужасная привычка, не имею в сложение всего этого метода, бла-бла-бла-бла-бла. Я провозглашаю, что функция выполняет более одной операции.
¶ — Флаги в функциях — всегда ли антипаттерн?
это не совсем так с одной стороны я как бы с ним согласен и флаги чаще всего это плохая идея но далеко не всегда это другая функция я могу Простейший пример привести — это, допустим, Markdown. То есть, когда вы рендерите Markdown, у вас, как правило, огромное количество опций того, как его рендерить. Отображать ссылки, не отображать, делать раз, два, три, четыре. И таких примеров можно привести еще много. Является ли это проблемой?
И, к сожалению, мы там передаем флаги, что-то делаем. Да нет, это нормальная задача, абсолютно логичная и стандартная. То есть так везде устроено. Разница просто скорее в том, что флаги передаются в таком случае не в виде просто аргументов. Они передаются, как правило, специальным кондинфигурационным объектом. Но тут, конечно, уже зависит от языка. То есть где-то в TypeScript или какой-нибудь динамике попроще, потому что там можно просто объект передавать.
В каком-нибудь Java это сильно сложнее сразу, потому что, допустим, если у вас есть набор конфигурационных параметров, которые надо передать, у вас как бы тут же сразу всплывает еще один класс. какой-нибудь configuration, что-нибудь, markdown, config, который вам надо отдельно создать, заполнить и, соответственно, передавать его дальше.
Либо, да, получается, когда на всё это смотрят, думают, нафиг надо, и просто пихают сто флагов туда. Ну вот, да. Так что проблемы, честно говоря, чаще, мне кажется, возникают вот в подобных языках, где простейшая история с передачей параметров.
конфигурационных параметров, она требует использования классов, а не просто простого инлайн-литерального какого-нибудь синтаксиса объектов, как, например, это в JCTagScript работает. Кстати, поэтому, да, там вербозности, конечно, гораздо больше в таких языках. Так, функцию с двумя аргументами понять сложнее, чем мунарную. Ну, хрень какая-то, блин. Если у вас функция суммы считает два аргумента, ничего сложного нет. Это уже притягивание за уши, тут надо смотреть в смыслы.
Клан мотаем дальше. Объекты как аргументы. Если функция должна получать более трех аргументов, весьма вероятно, что некоторые из этих аргументов стоит упаковывать в отдельном классе. Здесь вот как раз идет эта подмена понятий. Человек, который на Java не писал и читает эту книжку, он может неправильно понять вообще, о чем идет речь. Просто именно проблема в том, что в Java ты не можешь просто взять и передать набор параметров.
Их нужно упаковывать во что-то. А упаковывать там можно только в класс. Поэтому он и говорит об этом. Но по факту, что он имеет в виду, что их можно передать как набор опций. И в этом плане он абсолютно прав. Очень часто есть в функциях...
Очень важные параметры, без которых никак. Это вот прям то, что надо аргументами передавать. А есть, например, там какой-нибудь последний параметр, который называется Options. И там уже можно какие-то разные конфигурационные штуки передать. И да, в Java это надо делать классом. Ну, не только в Java. В C-Sharp, в Kotlin, я думаю, вряд ли сильно отличается. Ну, по крайней мере, на момент, когда я с этими языками сталкивался, там, конечно, так все было. Мало ли что там придумали еще дополнительно.
Дальше глаголы, ключевые слова. Ну, тут понятно, что это глаголы. Ой, давайте поговорим про побочные эффекты. Очень важная тема, в которой Мартин немножко путает. Сейчас мы поговорим, что имеется в виду. Значит, побочный эффект и суть ложь. Ваша функция обещает делать что-то одно, но делает что-то другое, скрытое от пользователя. Иногда она вновь неженна на изменениях переменной своего класса.
скажем, присваивает им значение переменных или глобальных переменных системы. В любом случае такая функция является коварной, вредоносной ложью, которая сейчас приводит к созданию противоестественных временных привязок других зависимостей. Для примера возьмем безвредный на... на первый взгляд, функцию из листинга. Функция использует стандартный алгоритм для проверки пары имя пользователя, пароль. Она означает true, false, там, тра-та-та.
Ну и в функции имеется побочный эффект. Сможете ли вы его обнаружить? Он приводит пример функции CheckPassword, в которой внутри есть session, ну, инициализация сессии. Почему? Я считаю, что то, что он делает, это вообще не очень классно. создает немножко извращенное восприятие реальности. Дело в том, что побочный эффект — это важно. У него, кстати, везде тут примеры сплошных побочных эффектов.
¶ — Главное правило: не вноси изменения при чтении
И вот перед этим он там показывал функции, всякие в райты и так далее. Там везде побочные эффекты, что-то он про это ни разу не говорил. Потому что он как бы говорит про побочные эффекты, но в реальности показывает другую проблему. То есть она, конечно, связана с побочными эффектами, но он неправильно...
определяет это как проблема побочных эффектов. То, что он здесь показывает, это очень известный распространенный принцип, который я часто привожу в пример. И говорю, что он как раз является одним из самых фундаментальных. И с ним мы сталкиваемся буквально в коде каждый день. Все. кто пишет код. Он называется Command Query Separation, то есть разделение команды запросов. Грубо говоря, у него есть другой способ описать себя. Он звучит примерно так. Задавай вопрос, не изменяй ответ.
То есть если вы пишете какой-то предикат или просто извлекаете данные, то, конечно, вы ни в коем случае не должны менять состояние системы. Очевидным образом, да. То есть если вы спрашиваете, админ ли пользователь, подходит ли пароль, конечно, в этот момент ничего менять нельзя.
Если у вас команда, запиши что-то, измени, создай, естественно, там будет побочный эффект. И это абсолютно не просто нормально, это правильно и так должно быть. Поэтому, когда он пишет, что побочный эффект суть ложь, ну, честно говоря, это... Вообще фраза, ну, я не знаю. Ну, нельзя здесь такую фразу писать. Дело не в побочных эффектах. Просто в местах, где вам нужно читать, не создавайте побочных эффектов.
При этом, конечно, если мы начинаем копать глубже, там все чуть хитрее, потому что мы такие скажем, окей, а как же, например, лейзи какой-нибудь, да, ленивая инициализация. А, например, вот бывают такие штуки, тоже самый стакой флоу. Ну или вообще статьи, да. Вот вы статью в браузере открываете,
И у вас сама статья — это чтение. По идее, везде в коде должно быть только чтение. И, кстати, поэтому даже вы такие можете подумать. О, я буду с реплики только для чтения читать данные все, да, чтобы там эффективно распределять нагрузку в бэке. А потом выясняется, что у вас есть счетчик просмотров. И вы такие, опа, казалось бы, да, вот мы читаем, а на самом деле еще меняем этот счетчик. А там еще, может быть, условия какие-то и правила. То есть, с одной стороны, не всегда возможно избежать.
И иногда это часть бизнеса. И тогда вам никакое программирование не поможет. Она просто против бизнеса в данном случае. Второе. Иногда это можно делать незаметно. То есть есть языки или системы, которые позволяют так сделать. Потому что не везде так можно сделать.
когда у вас чтение превращается в побочный эффект, связанный с ленивой загрузкой. И это тоже нормальный подход. Почему? Потому что снаружи при правильной имплементации человек никогда не узнает, что там вообще-то был побочный эффект. То есть все будет выглядеть так, как будто его не было. Ну, а если есть, собственно, какой-то операция, которую надо сделать, ну, это просто должно быть командой. Это не должно быть чек-пасворд, это должно быть сет-пасворд. Или еще что-то в этом духе. Вот и все.
При этом это не означает, что с побочными эффектами не надо как-то особенно работать. Не просто надо, а очень надо. Просто их надо к другому привязывать. И обычно этот принцип называют функциональное ядро. императивная оболочка. То есть идея в чем? В том, что код, который занимается логикой, он максимально отделен от, собственно, побочных эффектов. При этом побочные эффекты вынесены в отдельный уровень. То есть мы сохраняем, читаем, что-то делаем.
отдельно от программы. Я вот приведу сейчас очень классный пример, который хорошо это показывает. Допустим, у нас есть просто консольная утилита, которая берет на вход файлик, например, CVS. И из него делает отчет в каком-то другом формате, в XML. Или там доковском. И выдает. То есть вот очень простая программка. При этом внутри, ну, сколько там, ну, допустим, там тысяча строк кода.
Я периодически ставил такой эксперимент, я спрашивал у ребят разных, говорю, как вы думаете, сколько кода с побочным эффектом в этой функции? Побочными эффектами, да. Мы не говорим про побочные эффекты с точки зрения изменения каких-то переменных. То есть, понятно, что можно очень по-разному написать непосредственно код. Но я скорее больше именно про работу там в целом с внешними системами взаимодействия. И всегда, когда люди про это говорят, они такие 50%, 7%, 10%, там еще сколько-то процентов.
Я говорю, ну, смотрите, по большому счету побочных эффектов здесь даже в процентах так мало, что их можно проще посчитать по пальцам. Их тупо два. Первое — это прочитать файлик, второе — это записать файлик. И основная логика вашей программы в данном случае — это, собственно, формирование этого отчета. И получается, что фактически при правильном построении у вас получается наверху программы есть чтение.
исходного файла и запись его туда, а посередине функция, которая непосредственно строит этот отчет. И, соответственно, у вас таким образом разделены ответственности. И вот при таком подходе, при таком взгляде императивное ядро, в смысле функциональное императивное ядро, Вы из этого можете много-много разных выводов делать о том, как вообще надо писать код и на что обращать внимание. Внимательный слушатель и смотрятель моего подкаста скажет «Кирилл».
¶ — Стриминг данных: побочные эффекты в реальном времени
А ведь не совсем все так, потому что если ты так напишешь программу, это, конечно, очень классно, но если у тебя там файл на пару гигабайт, ты получишь очень эффективный код, потому что он загружает все это в память, жрет просто очень много всего, и, соответственно... всем приносит проблемы. И для того, чтобы это было реализовано правильно, нужно делать стриминг.
Правда, это все так и есть. Нужно читать данные порционно и выплевывать их, но при этом это не означает, что сама логика переплетена с этим стримингом. То есть это можно... очень грамотно все разносить. Хотя, конечно, сам побочный эффект растянется, но он может быть все равно довольно неплохо изолирован. Поехали дальше. Выходные аргументы. Аргументы, если образом, интерпретируются как входные данные функции.
Каждый, кто наверняка сталкивался с необходимостью дополнительной проверки аргументов, которые на самом деле оказывались выходными, а не входными. Пример. AppendFooter. Присоединяет ли эта функция S в качестве завершающего блока к чему-то другому, или она присоединяет какой-то завершающий блок?
Проблема вроде как бы есть, но проблема, честно говоря, связана с тем, что мы работаем с неявным состоянием. Кстати, еще вот он такую вещь рассказывает, которая кардинально поменялась за последние, там, несколько лет. Я думаю, за последние пять лет. Прям очень сильно.
и перестала быть проблемой. Значит, он здесь пишет про то, что надо смотреть сигнатуру. Он часто, кстати, приводит этот пример, что надо смотреть сигнатуру, надо смотреть сигнатуру, без сигнатур мы не поймем, и все очень плохо, если мы не видим сигнатуру.
Дело в том, что во всех современных редакторах, будь то Vim, будь то IntelliJ, будь то WaysCode, показываются все типы. Их нету в коде, но они показываются в файле, да. То есть мы, например, определяем переменную через вывод типов, просто там const, var или еще... как-то зависимость от языка но вообще-то там сразу показан какого она типа то же самое касается и лямбда функции как когда вы описываете их и внутри есть какие-то данные они вам все посвечивают определение вызовов и так далее короче
Сейчас это встроено везде, и проблема смотреть в сигнатуру, она, ну, ее нет просто. Мы это просто видим в коде по дефолту во всех современных редакторах. Это не заменяет никаких историй про то, что код должен быть понятным.
Но сама проблема, она как бы отсутствует. Вот. А то, что он здесь пытается описать, ну, это надо отдельно обсуждать, уже более глубоко про проектирование, потому что он такое начинает рассказывать, приводя плохой пример. А я считаю, что он вообще... Сам принцип организации кода, когда он здесь показывает, собственно,
report append footer, я вообще не согласен с таким кодом. То есть он изначально написал код, который, в принципе, писать не надо было. И такой говорит, ой, это неправильный код. При этом показывает здесь, как решение, вообще какую-то другую историю. Ну, как я уже говорил... Он убирает аргументы и перенося полностью стоит внутрь. Это не означает, что так нужно писать код. Вот.
¶ — Мартин против здравого смысла: перегибы автора
Ну, давайте не будем погружаться, говорю. Здесь надо прямо этот репортер брать, который он придумал, и смотреть, почему он вообще его так написал, потому что я бы написал по-другому. Он здесь как бы пишет про разделение команд и запросов. которую я только что рассказывал. Но прикол в том, что он это как бы отдельно делает. То есть вот то, что он про побочные эффекты сверху засунул, он не связал с этим. И поэтому люди, которые это читают, я уверен...
Даже не поймут, о чем идет речь, потому что здесь ничего не сказано про побочные эффекты. Вообще. Ну, с одной стороны, он говорит, что либо возвращать информацию об этом объекте, но здесь, во-первых, привязка, при чем здесь объект, это слишком джавовая история. Во-вторых, он опять упускает вот эту историю, связанную с побочными эффектами. То есть он так говорит, как будто здесь речь просто идет про изменение полей объекта. Ну нет.
Это же не об этом принцип. Хотя конкретный кейс, да. Это еще одна проблема в этой книжке. Он берет какую-то штуку, которую надо как-то посерьезнее обсудить со всех сторон, чтобы человек понял концепцию. Дает ее вот, знаете, в каком стиле? Он дает это в стиле шорцев каких-то или рилсов, когда очень коротко, очень такое броское, чтобы тебе в голову что-то вошло, но на выходе ты выходишь с мусором, потому что у тебя не формируют социальные картинки. То есть это не нормально.
такой последовательное описание принципов стране кода просто такой вспышка бам тут бам тут бам тут причем не связано, и из-за этого я не верю, что человек, прочитавший эту книгу, может выйти и, например, подробно, вот как я сейчас, например, рассказывал, рассказать про разделение команды запросов, связь, значит, с побочными эффектами, эти кейсы и так далее. Надо свою книжку писать.
на эту тему. Хотя уверен, что где-то это... Я же сам это где-то тоже читал все не раз в разных местах. Но вот интересно, есть ли такая книжка, которая подробно вот именно так все это описывает? Это хороший вопрос. Используйте исключение вместо возвращения кодов ошибок. Я вчера, когда готовился к записи и читал его немножко вот книжку заново, чтобы посмотреть, что он здесь пишет, вот посмеялся над этим пунктом, потому что когда он это писал, на Го еще мало кто писал, да? И...
Сейчас очень смешно то, что все, что он здесь пишет, полностью противоречит. То есть он это показывает как абсолютное зло. Он говорит, что возвращение кодов ошибок функциями является очевидным нарушением принципа разделения КАМАЗ-запросов. Хотя вообще это, честно говоря, здесь ни при чем. Он показывает код довольно типовой для Гошки и рассказывает, смотрите, какой кошмар. При этом он показывает слишком глубокую вложенность, опять же, там, где можно было написать по-другому.
Понятно, почему он это делает. Понятно, почему все это происходит. Скорее, правильно было бы написать, что, ребят, мы работаем в Java. Java — это язык с исключениями. У них есть определенные смыслы.
¶ — Как обрабатывать ошибки: изоляция try-catch
И мы определенным образом должны как бы с этим работать. Это не означает, что на каждую ситуацию мы бросили исключение, но мы работаем исключением. Получается, что работа с кодами ошибок — это просто писать против ветра, если мы работаем в Java. Но просто тупо с этой системой никто другой взаимодействовать не сможет, и она ни с кем не сможет нормально интегрироваться. Поэтому...
В данном случае это специфика джавовая, потому что человек, который, например, из той же Гошки или там Хаски для того же, да, где тоже нет исключений, по-другому это работает, читает вот эту штуку, он как бы вообще не поймет. А в чем смысл? То есть вроде чистый код, а какая-то такая супер большая специфика. Поэтому, да, есть языки, в которых вот так устроено, это абсолютно нормально. Можно, конечно, покрасивше, чем в ГО это было реализовать, но в любом случае...
Большинство людей, наоборот, счастливо. То есть замечаете, как бы он это рассказывает как абсолютное зло. Куча людей спрыгнула на такую систему, говорит, слава богу, мы больше не пишем исключения, у нас вот нет вот этого всего трэша. Так что вот так вот мир довольно... Быстро и сильно, как видите, меняется. Поехали дальше. Изолируйте блоки тройкич. Блоки тройкич выглядят весьма уродливо.
Любит он, конечно, закидывать, так что потом все... Возможно, кстати, весь успех его книг заключается в том, что он на вентилятор накидывает и делает так, что все потом срутся и постоянно его обсуждают. Так что допускаю, что это главный критерий успеха его книжек. Они запутывают структуру кода, смешивают обработкой с нормальной обработкой. Бла-бла-бла-бла-бла-бла-бла. Ну что, тут очень просто все. Исключение.
В идеале все-таки это какая-то обработка на самом верхнем уровне, а внутри кода это нормальная проверка какая-то, что можно сделать, что нельзя. Это не всегда возможно, есть всякие гоночки и так далее, но, наверное, против чего он здесь выступает в первую очередь, это, конечно, против того, чтобы жестко завязывать логику на это поведение.
Когда мы как go to, по сути, начинаем использовать исключение, чтобы практически в том же месте, где мы исключение бросаем, его ловить. Вот это очень такой паттерн действительно плохой. Сразу видно, что исключение в данном случае будет использоваться как логика.
Но в целом, опять же, не будем на этом сильно останавливаться, потому что с исключениями это прямо отдельная история, как они работают, как с ними правильно работать, и тем более не во всех языках они есть. Особенно сейчас, когда много и без него. Опять специфика Java. Поехали дальше.
Да, мы частично затрагивали структурное программирование. Он тут начал про него говорить. Наверное, зря я чуть раньше про это рассказал, про выход из функции. Но, в принципе, речь идет именно про это, что структурное программирование — подход, при котором вот мы... делаем ровно один выход. И это было связано, конечно, с большим использованием GoTo. Честно говоря, все это довольно давно не актуально, поэтому можно в эту сторону особо не смотреть.
¶ — Продолжение следует: разбор всей книги до конца!
Потому что сейчас у нас программа прямолинейная, если, конечно, мы тройкетчем там не используем для того, чтобы менять поведение. На этом первая часть закончена. Мы сегодня разобрали функции. Потом я буду разбирать остальные главы до тех пор, пока мы не пройдем всю книжку до конца. Если вам понравилось это видео, поставьте лайк.
Если нет, дизлайк. Обязательно напишите комментарий, если вы со мной не согласны, прям бомбаните по мне как следует. Если согласны, тоже что-нибудь напишите. Самое главное, мне очень важен любой ваш фидбэк для того, чтобы понять, как... что лучше говорить, что лучше не говорить. Может быть, я где-то ошибаюсь.
Может быть, вы для себя открыли что-то новенькое. И в конечном итоге мы пройдем полностью эту книжку, завершим. И дальше начнем уже разбирать не то, как не надо и где какие проблемы, а то, как классные, какие классные штуки существуют. Всем спасибо, пока.
