All streams
Search
Write a publication
Pull to refresh

Comments 134

Разумно. С этим "чистым кодом" задрали уже. Помнится, пару лет назад на каждом втором (если не чаще) собеседовании спрашивали мнение о книжке дядюшки Боба. Принципы SOLID сами по себе ни хороши, ни плохи: их, действительно, полезно знать и где возможно - применять. Но в отрыве от практики и реальности они - все та же всем известная сферическая лошадь в вакууме. Нормальная книжка, во-многом поучительная, но не надо делать из нее очередной объект поклонения вроде цитатника Мао. Сейчас, хвала небесам, немного успокоились, хотя порой и проскакивает.

Мне, к примеру, симпатичнее следовать https://ru.wikipedia.org/wiki/YAGNI. "Наворотить" сложное - дело не хитрое, но читать это, а тем более править и развивать, тоска зеленая. Например, у многих начинающих java-программистов, наслушавшихся гимнов во славу ООП, весьма распространен подход: каждый класс должен имплементировать какой-то интерфейс. Да, интерфейсы полезны - кто спорит. Но зачем доводить дело до маразма - ну никак не пойму. Программы по самые ноздри засраны (простите) кучей кода "на всякий случай" - а вдруг понадобится. В 99% случаев - не понадобится. Но мусор останется, в котором кому-то потом придется разбираться

Разумно. С этим "чистым кодом" задрали уже

Автор буквально пересказывает "чистый код" своими словами с шутеечками. Так "разумно" или "задрали"?

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

+1, зашёл, чтобы написать то же самое. Автор как бы противопоставляет себя-нитакусика мейнстриму, но в статье буквально подтверждает, что мейнстрим принципы нужны и логичны.

В чистом коде есть как полезное, так и вредное, например, передача контекста через поля класса. Смысл не в том, чтобы полностью проотрицать чистый код, а в том, чтобы перестать возводить его в роль идеала. Типа, писать чистый код сложно, тяжело, затратно, но мы к этом стремимся, потому что так правильно. Я против такого подхода.

Ещё сама фраза "чистый код" давит: если у тебя не чистый код, значит грязный, а если грязный, значит плохой.

Из чистого кода нужно взять хорошее, а плохое не нужно.

Больше того…

Я хоть и сам перфекционист, документацию люблю, к унификации всего и вся стремлюсь, но тут меня озарило:

Давайте возьмем легкую промышленность и тяжелую. Шо, там, станки унифицированы? Ты как инженер перейдешь с одного завода на другой, — а там вообще другой вендор тех-процесс. Все надо перестраивать в своей голове. (Так же и пилоты самолетов, кстати. Когда пересаживаешься за другую модель).

Или я как инженер связист. То ты в «циске» что-то крутишь, то «джупитер», то китайцы со своим интерфейсом заполонили… (да, это немного другое, но рядом)

И вот пришел ты на новый завод, а там… и тех процес тот-же вроде, но станки другого вендора. Цепочка пооизводственная устроена не лучше не хуже с точки зрения бизнеса, но! Но она другая…

И возникает то ли вопрос, то ли ответ — унификация это хорошо, но везде ее не впихнуть, видимо.

Мой внутренний перфекционист всплакнул.

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

Да! Я надеялся увидеть разумную критику "Чистого кода" - не раз на хабре такие статьи проскакивали, особенно, когда нужна производительность, - а прочитал пережеванный тот же "Чистый код" :(

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

"Чистый код" это всегда не обязательное требование. К нему лучше стремится - так как за каждым принципом стоит, чей-то пот и чьи-то деньги. А то что про него вместе с ИИ, нанотехнологиями и прочей ересью из каждого репродуктора кричат, то это совсем не чего не значит. Например солидная контора РосАтом(ГринАтом) на собеседование про SOLID спрашивают, в должностных обязанностях стоит - знание SOLID - но проекты у них написаны так, что там про SOLID даже не слышали. Какая единственная ответственность? Там что не функция - так Шива восьмерукая, какой принцип открытости закрытости? Там уже столько наменяли внутри, без расширений - что ногу сломаешь. В результате, как правило после выдачи результатов кандидаты сами с испытательного срока с проекта сбегают или их пинком высаживают за неэффективную работу. Есть конечно "гении" которые умудряются код писать, не боясь что все вокруг осыпятся. Но это же не правильно!!!!!

Легаси есть легаси. Они на собесах и спрашивают про солид потому что назрело. А тонны лапшекода были написаны давным-давно. Другое дело что всё это надо рефакторить и покрывать тестами где нужно, но на это времени не выделяют обычно. Потому что поток текущих тасков. За них спрашивают с тимлидов, а рефакторинг в KPI не напишешь.

Тонны лапшекода продолжают плодится и будут плодится там еще долго. А спрашивают там на собесах про SOLID по причине "модности". Да в KPI рефакторинг не вставишь, как и комментарии, нормальное название переменных, удаление циклических ссылок и прочей не эффективной ерунды. А для поднятие KPI можно просто сделать так - пришла задача - добавил пробелов - сделал коммит - попросил подельника апрув поставить и ты рад и тестировщик. Он может эту проблему еще раз 20 описать, повысив свой KPI - а программисты еще 20 раз "поправить'.

Мне кажется, это потому, что нет разумных метрик оценки работы программиста. Количество строк кода? Да элементарно, сколько надо в день: 200/300/500/800? Скорость реализации? Давайте вспомним выбор между скоростью разработки (временем), качеством и стоимостью. Никак больше 2-х не выбирается. Качество? Как его оценить, по результатам тестирований? Пока код не попадет в прод - все это, по большому счету, некое приближение и надежды, что оно не слетит, не развалится под нагрузкой и т.д. А безопасность, устойчивость, пригодность к развитию? Вот честно, я не знаю. Как по мне, главное - качество, пусть за счет скорости реализации. Тогда не будет искушения вставлять пробелы на пару с подельником. Но система устроена так, что только успевай одни дыры латать другими и городить велосипеды. Видел проектик на java как-то. В одном классе было штук 5 методов по 3-4 тысячи строк достаточно плотного кода. Какой там SOLID )))

Вопрос зачем оценивать? Дать премию например годовую? Или для продвижения по карьерной лестнице? Или просто цифры поставить, что бы в случае их изменений начать разбираться в причинах и начинать их чинить. И последствия таких оценок. Но это другая тема. Единственное можно сказать если стараешься писать чистый и понятный код - то KPI у тебя будет падать. Парадокс? Да. Об этом и говорилось.

Единственное можно сказать если стараешься писать чистый и понятный код - то KPI у тебя будет падать

Верно. И меня мой же руководитель зачпокает, поскольку его KPI тоже упадет. Со всеми вытекающими

Я видел, верю. Были скрипты, которые

a = 1

Превращали его то в True, то в char, проверки на валидность (Сотнями раз туда сюда), и затем

If a = 1 then

Что то сделать.

Машина Голдберга.

Написал дипсику: Есть функция в языке питон, ее смысл - принимает на вход число X и выдает Y. Функция сама по себе X = Y. Задача - написать на питоне эту функцию, чтобы не менее тысячи строк и минимум преобразование (речь идет о целых числах)

Ответ я приводить не буду, но он его дал и оно работает. И это ужасно, поверьте.

Зачем вы там работаете… выходит только ради денег? Или как такая работа может приносить хоть какое-то удовольствие… Мне правда интересно, не со зла, если ответ доход, то окей, пойму

Я программистом вообще не работаю и не работал. Когда я работал в АСУТП и пришлось разбирать древний код на Сях, который крутился на 486 компьютере. Кто его написал, мне неведомо, но видимо платили именно за количество строк, и это примерно середина 90ых. Или я не знаю, по какой причине можно так делать. Но делали же. И оно работало. И это была почти система реального времени (насколько это возможно под DOS), комп этот управлял самодельной платой на 51 контроллере, которая уже управляла через мощные внешние ключи термопласт-автоматом.

А еще могу рассказать короткий анекдот: Итальянцы-программисты. Конец анекдота ))

Если меня будут спрашивать про чистый код, solid и подобное я отвечу и, пожалуй спрошу

сколько времени они выделяют на рефакторинг чтобы обеспечить качество кода

Работал в проекте на 200'000 Java строк. Там главный разработчик очень любим наследование. У одного из классов было 7 уровней наследования, то есть существовало пра-пра-пра-прадед.

Да-да, и интерфейсы тоже любили. В том числе и пустые интерфейсы-флаги

Недавно в ВК такое чудо видел. Самописный фреймвор управления тасками. Логика не через инкапсуляцию в сервисах реализуется, а через бесконечные наследования базового класса. Как такое может появляться при таких собеседованиях - для меня загадка.

Код, который не заставляет вас напрягаться, чтобы понять его замысел

при чтении чужого кода я 99% времени трачу на понимание логики кода, а так как логика у каждого программиста своя, то не существует единого подхода. Нет, безусловно, мы можем воспитать тонны программистов пишущих шаблонами, но это же будут просто кодеры-функционеры. Возможно это и нужно кому-то.

А если переменная называется elapsedTimeInDays или activeUsers, вопросы отпадают сами собой

не совсем, сам факт чтения на английском названия переменной и якобы понимая что это за переменная - он полезен только в понятном контексте, а в непонятном - бесполезен, отсюда мы получаем что первично понимание логики программы (читайте абзац выше), а когда вы понимаете логику вам становится не важно d там или activeUsers.

Разделите ее на validateForm, saveUserToDatabase, sendWelcomeEmail

Главное потом не забыть везде в коде писать по три строчки вызовов подряд (вы кстати дальше сами с этим же и боритесь)

Создадим одну общую инструкцию для кормления

а вот выше вы написали что нельзя так делать )

Хороший код стремится быть самодокументируемым. Это значит, что его структура и именования настолько ясны, что комментарии, объясняющие, что он делает, становятся излишними.

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

Регулярные мини-рефакторинги. Увидел плохо названную переменную - переименуй. Заметил длинную функцию - разбей на две. Оставляй код немного чище, чем он был до тебя.

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

Создайте внутренние гайды. Договоритесь внутри команды об общих правилах и зафиксируйте их

Когда-то давно, еще в 2006 году, пришел на работу в банк, там местный дядя-одмин набивал текстовички с информацией где что происходит и как это решать. Для себя в 2013 году я добрался до формирование локальной базы знаний на DokuWiki, но самое интересное что пока я был один на том заводе и ко мне изредка брали помощников которые поработав немного уходили, то ту базу знаний я наполнял и ей сам же пользовался, а вот на последующих работах ни коллектив, ни начальство эту идею не подхватывали.

Читаемый код ускоряет разработку в долгосрочной перспективе

А современный бизнес не мыслит такими категориями, им нужно здесь и сейчас, а что будет поле нас - пофигу. Это проблема съедает целые корпорации.

Цель не в том, чтобы писать чистый код ради чистоты, а в том, чтобы писать поддерживаемый код там, где это действительно нужно. Ищите баланс, думайте о будущем вашего проекта и всегда задавайте себе вопрос: "Сделает ли это усложнение жизнь следующего разработчика (возможно, меня же) проще или сложнее?".

Жаль что так мыслят не те кто задаёт тон.

Разделите ее на validateForm, saveUserToDatabase, sendWelcomeEmail

Главное потом не забыть везде в коде писать по три строчки вызовов подряд (вы кстати дальше сами с этим же и боритесь)

Не надо не забывать. Функция handleUserData никуда не делась и как раз состоит из этих трех строчек вызовов.

так автор пишет про "function покормить_кота(имя_кота)"

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

по такой логике заливая фундамент под одноэтажный дом лучше залить его сразу под трехэтажный, а вдруг через 50 лет ваши внуки захотят 3 этажа строить?

если у меня задача хранить вектор 8 бит, то я не пишу софт под 64-битные векторы для "а вдруг".

Я возразил по совершенно другому приведенному вами примеру. И возразил справедливо, кмк. До кота мы еще не дошли, мы юзердату хэндлим пока )

Я возразил по совершенно другому приведенному вами примеру

одно связано с другим. если вы что-то еще имете в виду то объясните.

В мире вообще все связано. Однако вы пишете такое:

Тут вы предполагаете, что автор предлагает ЗАМЕНИТЬ функцию handleUserData на вызовы трех производных функций по ВСЕМУ коду. Не знаю, как иначе можно трактовать ваше замечание.
Тут вы предполагаете, что автор предлагает ЗАМЕНИТЬ функцию handleUserData на вызовы трех производных функций по ВСЕМУ коду. Не знаю, как иначе можно трактовать ваше замечание.

Однако же у автора написано совершенно другое:

Разделите ее на validateForm, saveUserToDatabase, sendWelcomeEmail. Сама функция теперь становится дирижером, а каждый кусок логики изолирован и понятен.

Вы успешно взяли у автора одно предложение и начали ему возражать. Но следующее за ним предложение делает ваше возражение несостоятельным.

Я вырвал этот фрагмент вашего комментария потому, что он мне показался самодостаточным. Ни текст перед ним, ни текст после него не делают его справедливым.

Остальные тезисы у вас достаточно субъективные, но с некоторыми, если не со всеми, я согласен. Но вот фактическую несостыковка среди них лишняя.

теперь я вас понял, да, это мой недогляд, претензию снимаю.

Главное, чтобы это была единственная публичная функция. Если все 4 доступны - всё становится ещё запутаннее.

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

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

при чтении чужого кода я 99% времени трачу на понимание логики кода, а так как логика у каждого программиста своя, то не существует единого подхода. 

Я думаю тут речь о чем то вроде грамматики в обычном (человеческом) языке, можно изъясняться расставляя слова как удобно и глаголы/прилагательные впихивая как каждому нравиться (ближайший пример - носители другого языка разговаривающие на русском). Но гораздо удобнее, чтоб все придерживались +- одинаковых правил, даже если они не оптимальны в мелочах. Да, все будут "шаблонными" в части языка, зато это позволить строить гораздо большие сущности вида целых статей или даже книг, которые другие люди смогут воспринимать без лишних сложностей.

что первично понимание логики программы (читайте абзац выше), а когда вы понимаете логику вам становится не важно d там или activeUsers.

Почему-то введение вами "первичного" критерия автоматом сделало "вторичный" критерий бесполезным. Понимание логики программы в том числе и строится на понимании что делает каждая её часть, а для этого и нужны такие имена. Нет хуже вещи, чем однобуквенные константы (если контекст не 5-10 строчек, конечно, ну или если это не что-то фундаментальное типа "i","j), особенно если их несколько штук, мгновенно начинаешь в них теряться.

а вот выше вы написали что нельзя так делать )

Неверно. Действие "покормить" - оно вполне одно. Тут речь когда есть концептуально разные по смыслу вещи.

То есть программист абсолютно не владеющий алгоритмом шифрования просто зайдя в код тут же магическим образом его изучит? Это так не работает.

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

Понимание логики программы в том числе и строится на понимании что делает каждая её часть

нет. "чужая душа - потёмки". чтобы понять логику вам нужно знать как минимум глобально что делает этот код, то есть вы знаете что например это функция которая применяет к картинке алгоритм Собеля. Но внутри у вас черный ящик. Погружаясь внутрь вы видите авторское исполнение алгоритма, если оно отличается от "классического по учебнику" то именования переменных возможно дадут вам информацию что как-то где-то что-то, но чтобы раскурить саму реализацию нужно именно знать ход мыслей автора, а если он при этом пользовался хаками двоичной арифметики, то вам и про эти хаки нужно уже знать, иначе вы увидите строку a = b & #AA7755FF и будете гадать что это за константа такая, при этом в самом Собеле об этом ни слова. Ну назовёт он не a, а FormatEdge и что вам с этого? Какой формат, какого ребра?

Нет хуже вещи, чем однобуквенные константы (если контекст не 5-10 строчек, конечно, ну или если это не что-то фундаментальное типа "i","j), особенно если их несколько штук, мгновенно начинаешь в них теряться.

Если вы в состоянии глядя на код понимать его логику ( а вы об этом и пишете), то нет никакой разницы однобуквенные там переменные или нет. А если вы не понимаете логику, то какая разница как названы переменные, вы же всё равно не врубаетесь что это такое. Ну вот вам пример выше про FormatEdge - что вам это даст? В Собеле нет ни слова про форматирование граней и загуглить вы ничего не сможете.

Я для примера уже давал код архиватора ZX0, до сих пор тишина, так никто ничего и не понял.

Именно так и работает, программист не знающий шифрования зайдёт в код, сразу поймёт, что тут происходит шифрование, что за шифрование и с какими параметрами

Какие волшебные у вас программисты ) Прям сразу? )))) Ну-ну.

В случае несамоописываемого кода программист скорей всего вообще ничего не поймёт, просто какие-то функции, которые что-то как-то делают, получают какие-то цифры, зачем-то что-то солят, делят зачем-то.

А, вон вы про что. Ну так и я могу - зайти, прочитать названия переменных и сказать - шеф, тут происходит шифрование. Мне дадут пирожок и премию 100 млн рублей. Так? Если вы не в курсе что там за шифрование и вы в этом не специализировались, то вы ничего там не поймёте. Знаний на планете чуть больше, ВСЕГДА, чем в вашей голове. Если вы ожидаете что кто-то будет писать код расписывая все детали и подписывая каждый чих - то удачи вам. В 90% случаев вы максимум получите те самые переменные состоящие хотя бы из пары букв, но вам даже такая красота ничем не поможет.

То есть ему сначала придётся угрохать кучу времени что бы вообще понять, что тут есть шифрование, затем понять как оно работает в теории, а потом ещё раз угрохать время, что бы понять, как оно конкретно в коде работает.

Именно так всегда и будет. Вы хоть когда-то работали с оперсорсом? Там же нам рассказывают что сидят идейные программисты, они всё красиво именуют и документируют ))) А там всё так же как и в проприетарном коде - разброд и шатания. Никто не будет писать код чтобы облегчить кому-то жизнь через 20 лет. Вон в NASA с Cobol встряли, думаете если бы там было всё расписано по феншуй то была бы разница кобол там или хрябол?

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


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

Ну вот вам пример выше про FormatEdge - что вам это даст? В Собеле нет ни слова про форматирование граней и загуглить вы ничего не сможете.

Если код самоописываемый то всё шифрование будет вынесено в отдельную функцию, которая будет называться по типу CustomImplementationSobelEncrioption (с передачей "говорящих" параметров) - (тема не моя не знаю как конкретно надо назвать, думаю вы сможете назвать лучше).
То есть вы ещё даже не зашли в функцию, но уже понимаете что примерно она будет делать, вам даже код читать не надо - а что гуглить вы уже знаете.
А теперь представьте, что вы не знаете что тут должно быть шифрование и видите функцию (или, что ещё страшнее - просто кучу кода внутри основной функции), с названием "GetStr(a,b,c)". Насколько быстро вы вообще поймете что там есть шифрование, что это реализация Собеля, да ещё и с кастомной реализацией.

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

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

 В 90% случаев вы максимум получите те самые переменные состоящие хотя бы из пары букв, но вам даже такая красота ничем не поможет.

Ну и хреново, с тех кто делает это бесплатно в опенсоурсе спросу нет, но вот в своей команде надо писать код грамотно, что бы потом твоя же команда не утонула в твоём говнокоде. И никаких 90% случаев так не будет, не надо тут за всех решать. Если у вас так - ну чтож, плохо. Особенно плохо - что вы продолжаете и множите это в своём коллективе.

 Знаний на планете чуть больше, ВСЕГДА, чем в вашей голове. Если вы ожидаете что кто-то будет писать код расписывая все детали и подписывая каждый чих - то удачи вам. 

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

Именно так всегда и будет. 

Нет, ну если вы всё время варитесь в легаси и говнокоде, или сами его порождаете - то да, так и будет. Но можно и иначе. И опенсорс тоже бывает разный.

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

ну так и качество кода абсолютно никак не влияет на ваши знания алгоритмов.

Во первых: ситуации, когда в коде есть знания, выходящие за имеющиеся у читающего относительно редки (в процентах)

И как вы подтвердите этот тезис?

если вы не работает с каким-то специфическим набором знаний

любые знания - это знания, обладание этими знаниями совсем не обязательный стандарт для вас или кого-то еще, только если вы не сидите на самописном проекте по 20 лет.

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

со второго раза? есть код который я изучаю уже лет 25 и пока не осилил, не то чтобы нужный код, но он требует прям приличного приложения усилий, и это меня останавливает, только вот чтение кода из раза в раз знаний так и не прибавляет. По сути нужно специально учить определенные темы.

ну вот вы изучили код, даже поняли его, но код плохой, ок, но вы знаете как он работает. Дальше что? Вы забыли всё через час? Или плохой код для вас уже не помеха? А что потребовало больше времени - плохой код или изучение алгоритма с нуля?

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

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

То есть вы ещё даже не зашли в функцию, но уже понимаете что примерно она будет делать

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

А теперь представьте, что вы не знаете что тут должно быть шифрование и видите функцию (или, что ещё страшнее - просто кучу кода внутри основной функции), с названием "GetStr(a,b,c)". Насколько быстро вы вообще поймете что там есть шифрование, что это реализация Собеля, да ещё и с кастомной реализацией.

(алгоритм Собеля никак не связан с шифрованием)

А чем принципиально для вас будут различаться два названия GetStr(a, b, c) и GetEncryption(a, b, c)? Для меня, кто не понимает что тут происходит, именование вообще не даст никакой подсказки.

Не понял о чем тут речь и к чему вопрос, если вы зачем-то читаете это код, значит с ним вам работать, значит вам надо его понять и как-то модифицировать/дописать

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

Быстрое понимание кода - быстрое решение поставленных задач

Безусловно, но вы быстрое понимание кода почему-то связываете с тем как будут обозваны переменные.

Если вы дошли до куска кода и сидите вникаете в него неделю/месяц - то вот тебе увольнение/закрытие проекта, а не пирожок.

Поэтому я не работаю программистом, потому что я не понимаю что пишут другие.

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

а вот с этим никто не спорит, ведь я пишу о понимании уже написанного чужого кода, а не создании здоровой рабочей атмосферы.

Если у вас так - ну чтож, плохо. Особенно плохо - что вы продолжаете и множите это в своём коллективе.

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

И опять

Нет, не опять. Знание алгоритмов у вас в голове не появляются с момента начала прочтения правильного кода. Сначала знание, потом код, а не наоборот. Наоборот - это реверс-инжениринг, тоже можно, но дано не всем и довольно сложное занятие.

Нет, ну если вы всё время варитесь в легаси и говнокоде, или сами его порождаете - то да, так и будет. Но можно и иначе. И опенсорс тоже бывает разный.

У меня нет привязки к каким-то конкретным языкам и проектам, я в силу своей увлеченности пархаю как бабочка от цветка к цветку, и разброд и шатания присущи всем, за 30 лет моего прибывания в интернете и чтения кода я не увидел никакого прогресса в сторону удобочитаемости и документированности, отсюда я склонен считать что ваши подвижки на личном фронте никак не влияют на средний показатель читаемости кода. Во всяком случае сколько я не коллективов прошёл, а доброе и светлое в организации работы никогда и никому нужно не было. Поэтому роль Дона Кихота я забросил лет 15 назад. А с приходом молодёжи, у которых по милларду IDE с ИИ в заду - я сижу в уголку и не отсвечиваю. Главное чтобы до пенсии дотянуть, а в постулаты правильности я не верю - всем на это плевать, особенно руководителям.

Безусловно, но вы быстрое понимание кода почему-то связываете с тем как будут обозваны переменные.

Ну если для вас понимание кода никак не связано с названиями переменных и функций, то попробуйте назвать все переменные var1, var2, ... var99, а функции, соответственно, func1, func2, ... func99.
Когда я вижу запись nameLen = strlen(name), я понимаю, как сформировано имя переменной и в дальнейшем по коду сразу вижу, что в ней находится. Когда я вижу zzz = myfunc1(xxx), то я должен сначала вспомнить, что же лежит в xxx, затем залезть в myfunc1 и понять, что она делает, и, наконец, запомнить, что именно будет храниться в zzz.

ну ок, вы знаете что в nameLen лежит число - дальше что? проблема в том что дальше этого знания вы не продвинитесь. поэтому если написано l = strlen(n) - это даст столько же информации, так как к моменту прочтения этой строки вы уже знаете что такое n, потому что где-то выше по коду вы встретили n = Strings.GetName(x);

ну и всё же, мы говорим про имена переменных, а не функций, это весьма разное. Как раз имя функции важно, так как при первичном обзоре кода вы можете массу вещей оставить в ситуации черных ящиков.

Зайдите в github проекта ZX0 и расскажите мне в деталях что же делает функция optimize(), а то независимо от именования мне совсем непонятен алгоритм. Вы же утверждаете что щелкает алгоритмы как орешки - покажите скилл, только не сливайтесь по придуманной отмазке.

если написано l = strlen(n) - это даст столько же информации

Ровно до тех пор, пока у вас только одна переменная с похожим именем. Как только у вас появляются l1, l2, l3, l4 и l5, запутаться в них проще простого.

Зайдите в github проекта ZX0 и расскажите мне в деталях что же делает функция optimize(), а то независимо от именования мне совсем непонятен алгоритм.

В деталях с ходу не скажу, но судя по названию и месту, в котором она вызывается, это предварительная подготовка данных для собственно алгоритма сжатия. Если функцию назвать func1 и вызывать её из функции func2, то вы и этого не сможете сказать.

Вы же утверждаете что щелкает алгоритмы как орешки

Где я такое утверждал? Вы меня с кем-то путаете.

Ровно до тех пор, пока у вас только одна переменная с похожим именем. Как только у вас появляются l1, l2, l3, l4 и l5, запутаться в них проще простого.

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

В деталях с ходу не скажу, но судя по названию и месту, в котором она вызывается, это предварительная подготовка данных для собственно алгоритма сжатия. Если функцию назвать func1 и вызывать её из функции func2, то вы и этого не сможете сказать.

а вопрос не в именовании этой функции а в её содержимом. расскажите что именно происходит внутри. (я знаю этот алгоритм и даже писал свой вариант на C#, но именно что свою реализацию, так как я не понимаю что именно и как делает автор внутри optimize(), я знаю даже на разных участках что он делает с данными, битами и т.п., но вот конкретность самой реализации я не понимаю совершенно, собственно я об этом и говорю, прочитать и понять чужой код это очень сложно)

Где я такое утверждал? Вы меня с кем-то путаете.

не путаю, но вы к беседе присоединились выбрав противоположную сторону, а значит вы согласны с этим.

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

не путаю, но вы к беседе присоединились выбрав противоположную сторону, а значит вы согласны с этим.

С чего бы это? Я заведомо согласен только с теми утверждениями, которые сам высказывал.

прочитать и понять чужой код это очень сложно

Бывает. Иногда проще оттрассировать код и посмотреть, что происходит при его выполнении. Но плохие имена переменных и функций явно не улучшат понимание. А вот хорошие могут. В том коде, что вы привели, есть функция elias_gamma_bits. Собственно, если вы знаете, что такое гамма-код Элиаса, то названия функции вам хватит, чтобы понять, что она делает. Если её назвать some_func_1, то вам придётся полностью её изучить, да ещё и понять, чему соответствует алгоритм функции.

В том коде, что вы привели, есть функция elias_gamma_bits. Собственно, если вы знаете, что такое гамма-код Элиаса, то названия функции вам хватит, чтобы понять, что она делает

даже если вы её назовёте мегафункция, я всё равно знаю из документации автора что он пользуется кодом Элиаса (у меня есть статья, можете убедиться что я в теме), так что для меня это вообще не проблема. Так что даже зная что делают функции в том коде я абсолютно не понимаю его реализацию, мне интересно узнать что он делает, а не как он именует функции и переменные, мне это вообще неинтересно.

Ну, досконально я не разбирался, но за пару часов понял примерно следующее.

Базовый анализ

Внешний цикл идёт по всем байтам данных (текущий байт).
Внутренний перебирает смещение в обратную сторону максимум на определённую в offset_limit глубину (старый байт).
Если текущий и старый байты не совпадают, то проверяется гипотеза копирования литерала.
Если байты совпадают и есть литерал с таким смещением, то проверяется гипотеза копирования с последнего смещения.
Если байты совпадают и длина совпадающей цепочки больше 1, то проверяется гипотеза копирования с нового смещения.
Для проверки гипотезы вычисляется длина блока при соответствующем варианте копирования и, если она меньше, чем уже найденная, то старый оптимальный вариант заменяется на найденный.
Последняя построенная цепочка (optimal[input_size - 1]) считается оптимальной и возвращается для записи в архив.
Функции assign и allocate нужны для ручного управления памятью и в языках с автоматическим контролем памяти могут быть заменены на присваивание и new соответственно.

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

то есть вы код оформили в виде псевдокода и считаете что это и есть понимание алгоритма?

Нет, я сначала понял часть кода, а потом записал то, что понял в виде псевдокода. Увы, но по другому своё понимание в чью-то голову вложить сложно.

то что вы описали видно по ходу чтения кода независимо от именования переменных, это просто последовательный набор действий, а не описание реализации алгоритма. как пример на том же вики большинство описаний алгоритмов описывают общими слова - трансформация, преобразование и т.п. хотя при программировании вы эти слова будете заменять конкретными действиями - создание хеш-таблицы чтобы А, преобразование в битовую маску чтобы Б и т.д. Собственно это и нужно в конечном итоге знать чтобы с этим работать. Само по себе описание ничего не даёт. Это просто типа "машина едет потому что работает ДВС" или "воздушный шар летит потому что внутри баллона лёгкий газ" - это слишком абстрактно. Да и даже если вы понимаете абстракцию, то понять код конкретной реализации часто весьма сложно - кто ж знает что было в голове у программиста??? я не знаю как еще донести эту мысль.

Хотите самое общее описание - пожалуйста.
Для каждого байта выбирается самый короткий способ его получить исходя из всех предыдущих байтов. Сложность квадратичная.

не хочу.

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

Так что именно "пока никто не смог"?

написать что же именно происходит в этом коде.

на основании вашего описания не получится повторить код, а как бы в этом и смысл разбора чужого кода. Постигать чужое обозначив крупными мазками - это тоже вариант, если вам нужно просто знание о том что тут сортировка, а тут сохранение файла. Но тогда ваше "сохранение файла" в вашей голове, оно же не будет совпадать с тем что написал автор. Вот и получается - вы прочитали название функции SaveToFile(String fn), и думаете что тема закрыта, а заходите внутрь, а там какая-то хитрая реализация, которая вместо сериализации массива делает хитрую обработку битовой маской, да еще так, что время получается O(1) а не O(n). И вот вы читаете код и нифига не понимаете.

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

нет. я преподавал много "информатику" и "программирование" и мы никогда не разговариваем на псевдокоде. Всё можно объяснить словами. Собственно смысл понимания реализации как раз в описательной части, а не мантрическом "если/то", важно как представлены данные и главное - время работы алгоритма, твики и т.п.

Хотел было ответить построчно, но понял, что это как плохой код - нечитабельно :).

Вы постоянно манипулируете утверждениями смешивая понимание алгоритма с пониманием/читабельностью кода.

Это разные вещи, разного уровня сущности! Я вам даже более чем наглядный пример привел - обычный язык.

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

Мне кажется тут всё более чем прозрачно.

 я не увидел никакого прогресса в сторону удобочитаемости и документированности, отсюда я склонен считать что ваши подвижки на личном фронте никак не влияют на средний показатель читаемости кода.

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

Вы постоянно манипулируете утверждениями смешивая понимание алгоритма с пониманием/читабельностью кода.

Это разные вещи, разного уровня сущности!

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

Расскажите мне что делается на всех этапах работы функции optimize() архиватора zx0, я за последние два года давал эту задачу многим, кто исповедует похожие с вашими принципы, пока ни один не смог мне дать ответ.

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

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

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

Главное потом не забыть везде в коде писать по три строчки вызовов подряд (вы кстати дальше сами с этим же и боритесь)

Где написано "везде в коде три вызова подряд"?

а вот выше вы написали что нельзя так делать )

Да где?!

То есть программист абсолютно не владеющий алгоритмом шифрования просто зайдя в код тут же магическим образом его изучит?

ad absurdum

Где написано "везде в коде три вызова подряд"?

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

Да где?!

Ну давайте вы будете внимательно читать и статью и мои комментарии.

ad absurdum

bet betmurdum

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

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

Он говорит про необязательность этих принципов

А тогда кто говорит про обязательность?

Отрицания НЕТ. Говорится что SOSAL должен преобладать над SOLID. Ну видать явные сторонники идей дядюшки Боба у него на проекте так идеи внедрять криво стали, что код не понятным стал. Хотя странно такое внедрение. Все пять принципов наоборот направлены на то, что бы код был структурирован и от этого читаемый.

Кажется, уже выросло поколение людей, которые книги Мартина и Фаулера знают чисто по срачам, а не по тексту.

Не могу не отметить, буквально сейчас претерпеваю именно этот процесс =)

Забавно, что в самом первом примере рефакторинга: arrow code продолбались и вместо мяты стала мышка, теперь кот обдолбан мышами
(LLM были здесь?)

Мой косяк. Нет, ллмок не было. Несколько раз переписывал статью с целью найти вариант, который проще читается и как то выделяет статью. Вот так и получилось

Это значит, что его структура и именования настолько ясны, что комментарии, объясняющие, что он делает, становятся излишними.

Каждое наименование класса, имя каждой переменной и каждого метода - это комментарии. С теми же недостатками: могут врать, устаревать или просто рассказывать не то, что надо.

Иногда таких комментариев хватает и нет необходимости писать `//`.

-- Дорогой, покорми кота.

-- Он сыт.

-- Ну как поссыт, покорми.

Извините, навеяло.

По существу. На мой взгляд конструкиция вида:

если (КОТ_ХОЧЕТ_ИГРАТЬ &&
      КОТ_В_ГОСТИННОЙ &&
      ПЛЕД_НА_ДИВАНЕ &&
      КОРОБКА_ПОД_ПЛЕДОМ &&
      МЯТА_В_КОРОБКЕ) {
    // запустить кота в коробку
} иначе {
    // что-то пошло не так
}

гораздо более понятна и занимает меньше места, а значит влезает на экран и охватывается одним вглядом, нежели предлагаемая "guard clauses". Но PKI конечно таким стилем программирования не поднимешь.

Очень часто вложенные условия как бы уточняют друг друга и выполняют промежуточные действия:

if (data != NULL) {
    response = request(data)
    if (response.succeeded) {
        result = process(response)
        if (result.valid) {
            store(result)
            и т.д. и т.п.
        }
    }
}

Такие проверки нельзя вычислить заранее и записать в одном условии, они плохо выглядят лесенкой, но зато элементарно и наглядно записываются с использованием раннего выхода.

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

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

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

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

Так что разных факторов полно и для их перечисления понадобится многотомник.

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

Меньше кода это не всегда хорошо. Опыт Perl и прочих хаскелей не даст соврать. Лесенку условий из примера выше можно легко переписать в столбик, типа:

processData data = do
    response <- MaybeT $ request data
    result <- MaybeT $ process response
    lift $ store result

Легче стало? - сомневаюсь. Кто же в здравом уме захочет потом в этом всем разбираться.

Потому я и написал: "Но это может не ко всему коду относится."

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

Да, и при этом еще может быть много ветвлений - Если соблюдены условия A, B, C - одна ветка, если A, B, D - другая, если A, C, D - третья... И так далее.

Множественные выходы тоже хорошо и красиво только в синтетических примерах. А в реальной практике отсутствие единой точки выхода может привнести немало проблем (как минимум, неудобств).

Хорошо, если язык поддерживает блоки on-exit куда обязательно попадаешь при любом (в т.ч. и аварийном) выходе. А если нет?

А теперь нужно возвращать сообщение почему нельзя запустить кота в коробку.

Нужно определить, что значит читаемость кода. Если по Мартину метод короткий и читаемый, но для того, чтобы понять, что он делает мне надо открыть 8 файлов, а в нескольких из них ещё мотать скролл туда сюда между private методами - ну как по мне это нечитаемая. Должен же быть какой-то баланс между SRP и размазыванием логики тонким слоем.

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

Защитники этой хрени аргументируют типа якобы рефакторить и вносить изменения проще. Да уже никто не пишет в тех отсталых IDE, в которых писал автор жёлтых книжек. Да и метрика какая-то тупая: код написан хорошо, если в меньших местах надо вносить изменения. Бред. IDE сама эту работу делает давно, мне только кнопку нажать.

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

У этой палки есть и обратная сторона.

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

Коты в среднем не одинаковые.

Особенно часто эти грабли в в КИСах встречаются ;-)

Что такое КИС?

Вот да. И там может быть столько разных if ....

Вот да. В моей тулзе есть два разных грида с разным кодом. Но внешне они выглядят совершенно одинаково. И я не "сушу" их до одной кодовой базы, потому что они "чуть-чуть" разные.

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

Если их пытаться наследовать друг от друга, то их фичи начнут перемножать сложность, это снизит надёжность каждого.

Имя должно раскрывать намерение. Если вы видите переменную d или list1, вам придется лезть *** знает куда или прокручивать код вверх, чтобы понять, что это. А если переменная называется elapsedTimeInDays или activeUsers, вопросы отпадают сами собой.

По-моему, это правило хорошо только для глобальных сущностей. Лично мне в локальных областях, о которых известно, что там происходит, проще разбираться, если переменные одно-двух буквенные, то есть когда не так:

for (indexOfElement = 0; indexOfElement < sizeOfArray; indexOfElement++)

array[indexOfElement] = ...

а вот так:

for (i = 0; i < n; i++)

array[i] = ...

Тут еще надо учитывать особенности восприятия слов человеческим мозгом. Часто встречаю имена переменных типа

dsYPS01LFk - структура ключевых полей индекса YPS01LF

dsYPS01LFi - структура записи индекса YPS01LF используемая для чтения

dsYPS01LFo - структура записи индекса YPS01LF используемая для записи

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

Т.е. переменные должны чисто визуально хорошо отличаться.

Даже во вложенных циклах

for (i = 0; i < 10; i++) {
  for (j = i; j < 10; j++) {
    ...
  }
}

читается хуже чем

for (i = 0; i < 10; i++) {
  for (n = i; n < 10; n++) {
    ...
  }
}

потому что визуально i и j схожи, а i и n отличаются по начертанию.

Ну, я бы сказал, что i и j это классика, поэтому их использование когнитивно прозрачнее. Туда же k при итерации по 3-мерному массиву.

А n... я бы напрягся, подумав - "а может оно определено выше и это общий размер массива?"

Тут речь о том, что когда внутри цикла много i и j, они имеют тенденцию визуально сливаться и перепутать можно достаточно легко, а чтобы найти ошибку потребуется "читать по слогам".

Не нравится n - пусть будет k. Главное, чтобы начертание отличалось от i.

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

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

Приятно встретить здравомыслящего человека :)

Догматы обычно показывают хороший результат на старте и плохой результат если в долгую.

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

Я бы тут поставил под сомнение еще пару вещей: SRP и код.ревью

А в плане архитектуры и понятности кода я копнул бы в сторону построения и понимания языка как такового, ведь каждый проект по сути описывается своим языком, в своих терминах. И понятный код - это когда код написан на понятном для всех участников языком. (Тут и DDD (изначальная задумка автора а не конкретные реализации) и BDD и DSL и семантика в тему, да и ООП можно приплюсовать (изначальная его задумка как раз про то чтобы удобно описывать системы языком программирования).)

Здравый смысл и антихрупкость всем!

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

Есть у него и здравые идеи, за что ему спасибо, например та же схема круговая Clean Architecture.

Правда её каждый понимает по своему и стремиться под это понимание прогнуть всех остальных.

Разбивка же на слои вполне адекватная. Хотя названия в этих слоях устаревшие, и не актуальные, что только запутывает.

P.S. Кстати я почти не встречал проектов которые действительно реализуют Clean Architecture. В основном люди тащат переусложнение и часть профита, но не понимают идеи в целом. Это же слои, Торт как сказал бы Осёл или Лук как сказал бы Шрек! А на проектах делают из этого селедку под шубой, тоже есть слои, но больше похоже на винегрет.

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

Автор не отрицает Чистый код и не агитирует за Чистый код. Автор про баланс. Сам как то написал модуль, где все как дядюшка Боб завещал. Опытный коллега сказал - "Нужен баланс". Через год переписал модуль - выкинул 90% интерфейсов, объединил слишком раздробленные обязанности и код стал намного проще в поддержке.
А про переменные/комментарии - не редко встречал, когда комменты безнадежно устаревали, а имена переменных/функций непросто "не о чем", а прямо лгут о своем намерении. При чтении такого кода приходится опускаться до деталей. Аж до уровня стрингов и интов. По итогу - мозгоусилий потратил столько же, сколько если бы сам реализовал фичу.

Баланс - его начинаешь чувствовать со временем.

если (кот хочет играть) { если (он в гостиной) {

Помнится, в 16 лет, на лабораторной по программированию в среде Турбо-Паскаль мне тоже не понравилось писать длинный развесистый if-then, и я вместо каждой булевской переменной завёл битовый флаг внутри целого числа: допустим, кот хочет играть было 00000001, он в гостиной было 00000010, а оба этих условия проверялись конструкцией если (это == 3). Вышло, действительно, сильно короче (насколько оправданно - другой вопрос), но препод охренел и отказывался ставить пятёрку, утверждая, что не будет работать. Наверное, это был "хитрожопый код".

Возможно, потому что это не очевидно и не всегда может работать. Флаги состояния могут расшириться, добавится какой-нибудь кот хочет есть = 00000100, и проверка может поломаться, кроме того проверка должна быть не на 3 а что-то вроде:
обстоятельства = кот хочет играть | он в гостиной
если ( это & обстоятельства == обстоятельства ) ...
Или что-то в этом роде, давно побитово не писал...

Всё там всегда работает, "поломаться" оно может, разве что, если число флагов превысит число бит в самом длинном числе, представленном в среде Турбо-Паскаль. К моему счастью, можно было просто продемонстрировать на компьютере, что всё работает. К чести того препода, он не стал говниться, извинился и таки поставил пятёрку.

Другой вопрос, стоило ли так выделываться. Но, с другой стороны, я не знаю, чем в парадигме "чистого", "понятного" и какого там ещё кода лучше заменить развесистый вложенный if, особенно когда истинны должны быть не все условия разом (тогда-то я бы вообще, наверное, написал на Питоне if all([кот того, кот сего, кот этого, ...]): обдолбать()), а в каких-то разнообразных комбинациях.

В функциональщине (или, с вашего позволения, type driven development) каждый кейс можно представить в виде типа и воспользоваться pattern matching. Скажу честно, я последнее время так и делаю.

А вместо побочного эффекта по обдалбыванию кота возвращать его обдолбанную копию?

Не читал никакого Мартина - мой код и архитектура и так всегда были чистыми.

Сейчас с распространением кодинг ассистентов понятие когнитивный нагрузки и размера контекста стало даже вполне осязаемым. Причём его теперь можно померить не только в токенах, но и - деньгах. Чем более запутанный код, тем более дорогие модели приходится использовать, и это моментально бьёт по костам.

через «о» же пишеццо
и кто такие «программиасты» и нафига им «бибмотека»?

неромазня в тексты всё ещё слабовато умеет

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

Функция должна делать что-то одно

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

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

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

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

Слишком длинную сложнее воспринимать.

Зависит от.

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

Однако проще читать функцию, если она вызывает несколько функций с говорящими названиями, чем то же самое, но в виде простыни кода. Например, если вы видите функцию string strToUpperCase(string s), то вряд ли вам надо погружаться в её код, чтобы понять, что именно она делает. А если к ней ещё и добавлен doc-блок, отображаемый IDE, то описание функции и её аргументов вы увидите при наведении на её вызов.
Тут надо только, чтобы разбиение на подфункции не было искусственным. Они должны быть достаточно самодостаточными и законченными по смыслу.

Тут надо только, чтобы разбиение на подфункции не было искусственным. Они должны быть достаточно самодостаточными и законченными по смыслу.

Вот-вот.

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

strToUpperCase подходит, да - её очевидно можно вызвать в другом контексте. Но я видел вполне себе продакта, который бил на функции, чтобы было много мелких функций - то, что работало в виде нескольких If-ов (да, на пару страниц, но там было все понятно), разбивалось на функции, которые работали в строго определенном контексте и никогда больше нигде не вызывались. Смысла в этом не видел.

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

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

Например, мы пишем функцию шифрования и в ней есть достаточно большой блок инициализации.

Имхо вот тут уже на вкус....
Я бы тупо обрамил этот кусок комментариями. Читающий специалист поймет: "инициализация" (а неспециалисту лезть в этот код не надо).

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

Опять же - предположим, у нас дебаг, что-то не работает. Есть шанс, что неверная инициализация проведена. Какова вероятность, что человек полезет в подфункцию, а не будет долго и безуспешно исследовать основной алгоритм, полагая "уж в инициализации не могли налажать".

Есть шанс, что неверная инициализация проведена.

Для этого есть покрытие тестами. И сделать тест инициализации гораздо проще, если она вынесена в отдельную функцию.

Покрытие тестами - да, аргумент - и я писал об этом здесь, чуть ниже: https://habr.com/ru/articles/952300/comments/#comment_28910320

Но даже покрытие тестами означает, что функция используется минимум ДВА раза - т.е. повторно. И в данном случае архитектура немного подстраивается под второй кейс использования кода - автоматическое тестирование.

Но даже покрытие тестами означает, что функция используется минимум ДВА раза - т.е. повторно.

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

еще удобно писать тесты на куски кода которые оформлены в функции. пусть даже эти функции используются единожды

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

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

Ооо, начинается (очередная) революция!

Кто-нибудь вообще видел чистый код в каком-нибудь рабочем проекте?

Видел) В паре проектов за последние лет пять. Но есть нюансы.

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

Второй - проект с нуля с очень сильной командой, начали с основательной проработки архитектуры и подходов, что помогло нам через полгода. Скорость поддержки и починки багов отличалась местами в несколько раз, по сравнению с аналогичной старой фичей, чисто за счёт грамотной, хоть и сложной архитектуры.

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

Теперь можно срать на ковер - робот-пылесос все приберет за вас

Ну или размажет по всей комнате тонким слоем =)

Дадим этим числам понятные имена.

сonst СОСТОЯНИЕ_МУРЧАЩИЙ = 1;
const СОСТОЯНИЕ_ГОЛОДНЫЙ = 2;
const СОСТОЯНИЕ_МЕРТВЫЙ = 3;


Есть же Enum…

Не знаю как в Go, но на Си в РФ 70-80% программистов с 15+ лет опыта не знаю, что такое Enum, битовые поля и объединения. Среди них 60-70% не знают про оператор switch.
https://habr.com/ru/articles/837396/

Микроконтроллеры свой, отдельный мир. И очень странный в плане качества. Достаточно вспомнить результат анализа кода Toytota от NASA в связи с известной историй про педаль газа...

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

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

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

покормить_кота("Барсик"); покормить_кота("Мурзик");

голодные_коты = ["Барсик", "Мурзик"];

голодные_коты.forEach(кот => покормить_кота(кот));

голодные_коты.forEach(покормить_кота);

в .net до некоторых пор лямбды сильно выигрывали в производительности у method group (MS накосячили, сейчас потихоньку фиксят).

Проблема в том, что очень многие неправильно воспринимают эти подходы.

Это же призыв - ребята сформируйте у себя в команде и проекте единые и четкие соглашения, основанные на здравом смысле. И такие, которые бы были понятны окружающим. А многие превращают в карго культ и ...

Принцип единственной ответственности (SRP). Функция должна делать что-то одно и делать это хорошо. Когда вы видите функцию handleUserData, которая и получает данные из формы, и валидирует их, и сохраняет в базу, и отправляет email, - это красный флаг.

Боюсь, вы не понимаете SRP. Почитайте, даже здесь, на "Хабре", этот вопрос разжевывался много раз.

Постоянно все нацелено на скорость и бабки, а не на качество и оптимизацию...

Вот это я понимаю, популярная тема. Все кому не лень написали своё мнение. Теперь моя очередь, хотя вряд-ли кто-то его вообще прочитает среди такого количества.

А вот согласитесь, все таки здорово что все эти SOLID, DRY, KISS, YAGNI принципы существуют, так же как и шаблоны проектирования. Мы все их знаем, понимаем, где-то что-то используем, распознаём в коде, и вообще обсуждаем структуру решений в этих терминах. Как-то сложнее было бы на пальцах всегда без них. Но что сейчас особенно важно и актуально, так это то что эти принципы теперь понимает и использует ИИ для генерации кода. Тем самым мы можем быть немного более уверены в качестве кода, если он следует этим принципам. Вместо бремени на реализацию это превращается в контроль над качеством.

А теперь представьте, что вы разрабатываете не маленькую фичу, а очень большое корпоративное приложение чужими руками (будь то люди или ИИ) и у вас есть возможность либо принудить всех следовать тому же SOLID, либо разрешить всем "решать на месте индивидуально". Что бы вы выбрали, согласованность или зоопарк? В обоих вариантах будут где-то менее где-то более удачные реализации. Но согласитесь, что следование общим принципам будет намного более выйгрышным в глобальном плане для проекта.

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

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

Кроме того, когда работаем с многими человеками, лучше создавать согласованное решение. Иначе каждый начинает писать кто во что горазд. Особенно это заметно, когда команда меняется. Правда не всё так просто: чем больше приложение, тем подробнее и сложнее становятся регламенты и соглашения в своей попытке закрыть все аспекты разработки. Хорошо, если есть возможность сделать приложения поменьше (микросервисы?), тогда согласования будет попроще и следовать им будут из-за этого чаще.

Читаешь и понимаешь, что буквально все антипаттерны реализованы как в легаси так и в новом коде на работе и хочется плакоц от того, что все члены команды кто в лес, кто по дрова (

Худшее, что можно сделать с guard clauses - это смешать их с вложенными условиями, особенно попеременно.

Особенно попеременно. После этого код становится абсолютно нечитаемым и крайне осложнённым для понимания.

Sign up to leave a comment.

Articles