Комментарии 151
Q: Почему вы не пытаетесь объяснять код дальше?
A: Лень писать 100 слов на одну строку.
Q: Понятно...
(это мой ответ, но не везде)
Если копнуть глубже: как вы решаете конфликт между SOLID-принципами (например, Single Responsibility) и необходимостью проектировать горизонтально масштабируемые компоненты в высоконагруженных системах? Например, микросервисы с избыточными абстракциями могут порождать latency или сложности в orchestration.
Есть ли у вас примеры, где оптимизация архитектурных границ (через DDD, event-driven и т.п.) оказалась критичнее, чем рефакторинг «грязного» кода?
Нет у автора статьи примеров и нет возможности копнуть грубже. Это ГПТ-творчество. Возможно, привлекали человеческого редактора к сведению текста или умеют работать с ароматами, когда собирают цельную статью...
Даю поправку. Данная статья — это совместное творчество человека и ИскИна ;-)
В комментариях представитель авторского коллектива появляется и отвечает более-менее по делу. А еще он (человек, но с современным развитием технологий возможно, что и AI-агент) умеет обижаться, что я почувствовал по карме ;-D
А с литературной точки зрения стоит сказать, что читается довольно неплохо. И информацией статья несильно перегружена
Если хочется посмотреть антипример, то гляньте еще одну недавнюю статью:
https://habr.com/ru/articles/906668/
"Как обогнать 99% Python-разработчиков с фокусом на эру ИИ — по версии ИИ (гайд), но это не точно". Там тоже есть ссылка на ТГ-канал, длинная простыня текста с обилием умных слов и аббревиатур, но там AI-monkey-автор не смог проверить логическую связность текста и убрать GPT-форматирование.
Возвращаясь к текущей статье. Мне больше всего резануло глаз некоторые упрощения, но, возможно, это компромисс, который диктуется объемом текста...
Например,
Чистый код, применяемый к разным языкам
Правила чистого кода остаются одинаковыми для всех языков программирования, но вот некоторые особенности, характерные для каждого языка.
...
HTML
Уберите лишние и повторяющиеся теги, оставьте только то, что действительно нужно, чтобы структура страницы осталась простой и прозрачной.
Существуют также полезные инструменты для создания чистого кода, некоторые из которых специфичны для того или иного языка.
Звучит это, на мой взгляд, так:
Чтобы уберечься от кишечных инфекций, тщательно мойте руки перед едой.
Также существуют другие способы очистки рук, если вода труднодоступна.
И информацией статья несильно перегружена
Я бы сказал сильно не догружена. Уже в самом начале структурированный код называется спагетти. В "плохом коде" зачем-то вдруг реализована сортировка пузырьком вместо вызова библиотечной функции. Ну а полную чушь в "особенностях языков" вы и сами отметили.
Но самое печальное, что этот продукт жизнедеятельности ИскИна получает +37 рейтинга. В то время как куда более глубокий анализ чистоты кода получает -6. Похоже восстание машин на Хабре уже достигло кульминации.
Но самое печальное, что этот продукт жизнедеятельности ИскИна получает +37 рейтинга. В то время как куда более глубокий анализ чистоты кода получает -6. Похоже восстание машин на Хабре уже достигло кульминации
Вот честно, мне бы тоже хотелось, чтобы у вас было побольше кармы и заплюсованных статей (особенно про $mol). Но ваша привычка на конкретные вопросы сыпать ссылками на лонгриды и часовые видео, несколько расстраивает.
Извиняюсь за непрошенные советы.
Спасибо за поднятую тему о конфликте SRP. После изучения практик крупных тех-гигантов, могу сказать, что архитектурные и инфраструктурные оптимизации приносят куда больше эффекта, чем попытка «почистить» каждый метод в отдельности.
Напримерр, в Java-сервисе Netflix (GS2) при переносе с m5.4xlarge на m5.12xlarge ожидаемый линейный рост не подтвердился — фактическое улучшение оказалось существенно ниже. При микроархитектурном анализе выяснилось, что имеет место false sharing : соседние поля в объекте конкурировали за одну кеш-линию, генерируя постоянные инвалидации и просадки throughput. Добавиление 56-байтный padding – и voilа: ≈3.5× рост RPS и заметное снижение как средней, так и 99-го процентиля задержки.
Тут хорошо видно, как локальные проблемы на уровне железа могут полностью «съесть» масштабируемость, даже при честном соблюдении принципов проектирования.
Другой пример — AWS Local Zones. Netflix перенёс часть latency-sensitive логики ближе к студиям аниматоров, и теперь художники получают однозначные миллисекундные задержки при интерактивном рендеринге графики — чего невозможно добиться при кросс-региональном вызове. При этом внутри объединённых процессов соблюдаются чёткие DDD-bounded contexts и event-driven обмен, так что поддерживаемость и масштабируемость не страдают.
и снова видно, что инфрастр. решение зачастую даёт больший выигрыш, чем идеальная SRP-архитектура, особенно в условиях real-time.
Так что именно такой микс «умных» границ и продуманных инженерных приёмов зачастую сильнее тысячи правок Code Smells. Этот ответ подпитан свежей кружкой кофе и старыми добрыми статьями тех-блогов :)
У нас в команде был показательный кейс: полгода вылизывали код, дробили сервисы по SOLID, выносили всё в общие библиотеки — в итоге получили «идеальный» монолит в распределённой обёртке. Каждый микросервис блестел чистотой, но при попытке масштабировать систему упёрлись в адские cross-service зависимости. Например, сервис нотификаций вызывал 5 других сервисов через цепочку RPC, чтобы собрать данные для письма — латенси ползла в ..
Пришлось экстренно пересматривать архитектуру: слепить несколько сервисов обратно в рамках bounded context, разрешить контролируемое дублирование DTO и убить «общие» библиотеки. Код внутри сервисов стал менее «чистым» (например, появились god-классы для локальной агрегации данных), но общая система задышала.
Сейчас ловлю себя на мысли, что архитектурные решения вроде верного разделения контекстов дают на порядок больше, чем рефакторинг ради следования принципам. Коллеги, как вы определяете точку, где пора остановить рефакторинг и переключиться на перепроектирование границ? Есть ли у вас метрики (типа коэффициента связности сервисов) или больше через боль и крики бизнеса?
Какое отношение SOLID имеет к распределенной архитектуре? SOLID это про организацию кода внутри одного приложения, а не про микросервисы.
Ну вообще можно рассматривать микросервисы как классы (они инкапсулируют догику, обмениваются сообщениями с другими микросервисами, даже инстансов бывает несколько). Так что солид можно применять и к ним в том числе, например, для инверсий зависимостей, ну вы поняли :)
Да. Я искренне не понимаю о чем пишут комментаторы здесь. Я бы ограничил область применения SOLID методами и классами. Целое приложение — это слишком большая область видимости для SOLID.
Я вообще не использую SOLID. Похоже, он просто не нужен.
Сейчас DDD это уже база для любой разработки, что монолит что микросервисов. Неправильное разделение на контексты действительно породит кучу проблем, поэтому в DDD уделяется этому большое внимание и все специалисты говорят не делать наносервисы. Мы тоже обожглись, когда разделяли монолит решили "на будущее" сразу сделать Уведомления + Email сервис (для отправки писем) + Telegram Service (для уведов напрямую). В итоге если сразу правильно все продумали, то не плодили бы эти лишние сервисы, потому что по-сути все это контекст уведомлений и не нужно было ничего лишнего добавлять. SOLID / KISS/ DRY при этом не противоречат DDD, просто надо правильно интерпретировать эти методологии
SOLID как раз про уменьшение зависимостей. Общие библиотеки и запрет дублирования DTO часто ведут к нарушению принципа открытости-закрытости.
Коллеги, как вы определяете точку, где пора остановить рефакторинг и переключиться на перепроектирование границ? Есть ли у вас метрики (типа коэффициента связности сервисов) или больше через боль и крики бизнеса?
По-моему опыту, на первое место надо ставить здравый смысл. А метрики и разные аббревиатуры нужны только, чтобы убедиться, что здравый смысл не зарулил куда-то не туда.
Например, сервис нотификаций вызывал 5 других сервисов через цепочку RPC, чтобы собрать данные для письма — латенси ползла в ..
От подобных неприятных сюрпризов защищает очень простой прием: всегда моделируйте потоки данных. Даже если это монолит, поток данных между сервером приложений и БД нуждается в контроле не меньше, чем между клиентом и сервером приложений. Если вы сначала проектируете API и только потом его реализуете, то вся необходимая информация должна быть уже на этапе проекта: берем каждую точку внешнего API; отслеживаем полный граф вызовов для выполнения запроса к этой точке; честно отвечаем себе, является ли этот граф разумным.
Если вы работаете в конторе, где менеджмент предпочитает метрики здравому смыслу, этот прием можно упаковать во что-нибудь типа "длина типичного (кратчайшего, наихудшего) пути выполнения запроса", который считать для каждого типа запроса по количеству пересечений границ сервисов, совершаемых потоками данных по пути от начала запроса до отправки ответа. Какое значение этой метрики считать хорошим не скажу, сильно зависит и от решаемой задачи, и от условий, в которых она решается. И, разумеется, ее надо не минимизировать (так вы можете прийти только к монолиту), а выставить верхний порог, превышение которого будет сигнализировать о подозрительности архитектуры.
У меня есть другой пример. Допустим, есть идея стартапа которая должна покорить мир в ближайшем будущем. Мы набираем команду разработчиков которые профессионально подходят к своему делу, пишут документацию с первого дня, рисуют схемы, делают код-ревью, разносят код на модули и библиотеки, покрытие тестами приближается к 100%. Надеюсь ни для кого не секрет, что это всё занимает чуть больше времени чем просто реализация через спагетти-код. В итоге может получится, что когда распрекрасно-чистый код дойдёт до продакшена, идея потеряет свою актуальность. Еще может стать, что кто-то чуть менее принципиальный уже давно в проде и захватил весь рынок. К чему это всё, к тому, что в реальной жизни самурайский принцип не подходит и цель важнее пути.
Мартин Фаулер приводил своё видение данного вопроса. Сначала скорость написания методом говнокода действительно выше, но потом она сравнивается с чистым кодом и начинает безбожно отставать. Его мнение, что период до пересечения занимает меньше месяца.
скорости можно добиться урезанием фич, а не качества.
Неблагодарное дело спорить с корифеями, но, как мне кажется, столь категорично устанавливать сроки в разработке неправильно. Не будет там месяца. Месяц уйдёт на то, чтобы все успели переругаться на тему как правильно называть функции (утрированно). За это время говно-код комадна уже выпустит альфу. Вообще к чему это всё. На начальном этапе фокус на чистный код и архитектуру может сыграть дурную шутку и погубить проект. Пусть это будет болью, но заниматься рефакторингом лучше уже на готовом продукте.
Это организационный вопрос, который решается элементарно: за каждым разработчиком закрепляется его зона ответственности, где за ним последнее слово. На этом все споры заканчиваются и каждый спокойно пилит свою часть задачи.
Тогда у Вас получается закостенелая структура, в которой появляются свои риски. Когда, например, выпадает разработчик за которым была закреплена зона ответственноти, выпадает и сама зона.
Не выпадает. Ответственность переходит к другому, знакомому с кодом, разработчику. Тут у него появляется возможность отрефакторить его под себя, если что-то не устраивает.
Есть очень большое сомнение, что "отрефакторить под себя" займёт нулевое время, особено при солидном объёме кодовой базы. Опять же, что значит под себя. Разработчики в конечном итоге делают всё не для себя, а для проекта в целом.
Основная идея рефакторинга: рефакторинг делается перед внесением изменений. Не отдельными тикетами, как считают некоторые олухи.
Поэтому он делается под себя! Потому, что потом сам вносишь изменения.
Разработчик, в действительности, делат для себя. Потом для команды. Потому для начальников и прочих манагерков. То есть для людей. А потом уже для проекта.
Знания то не переходят. Приходится разбираться. У меня есть большой опыт копания в запутанном коде без тестов. Занимает много времени.
Отрефакторить под себя код другого разработчика, пока он в отпуске? Вот он удивится.
Общие стандарты и кодревью уменьшают время понимания кода и убирают необходимость в рефакторинге под себя.
Если удивится. То это однозначно сразу ногой по морде. Вот даже не думая. Если это не аутсорсинг, конечно, где через каждые три месяца новые люди. И команда работает над тикетами, а не над проектом.
Написание тестов - первый шаг любого рефакторинга. Но было бы странно заехав в гости, сразу переставлять мебель под себя.
Вас немного в другую степь понесло. Прцитирую ваши тезисы
за каждым разработчиком закрепляется его зона ответственности, где за ним последнее слово.
Не выпадает. Ответственность переходит к другому, знакомому с кодом, разработчику. Тут у него появляется возможность отрефакторить его под себя, если что-то не устраивает.
Вот перешёл код на две недели другому разработчику, который концептуально не согласен ни с подходом, ни с форматированием.
Что ему в этом чужом коде делать? Писать как правильно или мимикрировать под другого человека?
Тесты уже должны быть. Если их нет, то скорее всего для тестов придется делать предварительный рефакторинг.
Я в одной из команд именно так и работал. Хорошо получалась. У каждого была зона с наибольшими контрибюциями. Хотя все работали во всех зонах, помимо своей. Получалось очень хорошо. У каждого были выработанны паттерны в рамках своей зоны, их форсили применять при ревью кода, относящегося к зоне.
Если команда ругается, то скорее всего не получится и говнокодить в сжатые сроки.
Выпустить демо, показать заказчику, получить денег, выкинуть альфу и написать нормально. Но так не работает, просто начинают расширять этот аморфный монолит который не протестировать.
С опытом базовая архитектура и работающие практики можно применять с первого дня и это не дорого.
Работал однажды в таком стартапе, в сильной команде, все очень ответственно относились к делу, старались выдавать чистый код и делать все максимально правильно.. Стартап помер. Прод так толком и не заработал, фичи делались с лютыми муками из-за оверинжиниринга, там где в обычном монолите, пускай даже сляпанном в духе - "херак-херак" можно было реализовать ее за пару дней, в этом "правильном" уходило от пары недель до месяца. Все тонуло в бесконечных межсервисных связях, распределенных транзакциях и прочих "красотах". Когда на новой работе увидел классический кусок легаси-монолита, так даже некоторое облегчение испытал, его поддерживать было куда как проще, даже с учетом наслоений древности.
Работал однажды в таком стартапе, в сильной команде, все очень ответственно относились к делу, старались выдавать чистый код и делать все максимально правильно.
Судя по дальнейшему описанию, старались но не вышло.
Я участвовал в двух проектах с микросервисами. В одном они были по делу, с апи фёрст, с разными языками, с масштабированием. А в другом, потому что так решил заказчик. Ни одного другого аргумента для неё не было.
Ещё заказчик заказал гексагональную архитектуру. На гексагональную архитектуру ругались, что она сложная и неудобная, оверинжениринг и всё такое. Правда, то, что ей называли ей не являлось.
Это я к тому, что технология применённая не по назначению, это не чистый код. И если в банке с надписью сахар, лежит соль, не надо кричать, что сахар горький.
Поправлю только: "реализовать ее за пару дней" читать как "реализовать хэпи пас за пару дней"
Понятно что это грубая и абстрактная оценка, но реальность именно такая была - из-за оверинжиниринга, совершенно бессмысленного на данном этапе развития системы (никакой суперпроизводительности не было нужно, потому что нагрузка на нее была смешной, там один сервер-монолит не напрягаясь справился бы и еще и с хорошим запасом) трудоемкость внедрения новых фич просто зашкаливала.
Чистый код и чистая архитектура никак не связана с декомпозицией предметной области. Это значит, что каким бы не был код, а софт перписывается несколько раз, и только на 3-4 итерацию получается более менее осознать потребности бизнеса и как эти потребности отражать в коде. Да и вообще лучше писать умные вещи тупым кодом, чем тупые - умным
Чистый код и чистая архитектура никак не связана с декомпозицией предметной области.
Ещё как связанна. S в солиде как раз об этом.
То что в предметной области понятно в одни модули, то что не понятно(заказчик не может определиться) в другие, то что будет меняться (например нормативные акты) в третьи.
Это делается, чтобы переписывать не всё, а только часть модулей. Да возможно придётся пересобрать модули по другому, но это проще, чем пересобрать спагетти-код.
То что в предметной области понятно в одни модули, то что не понятно(заказчик не может определиться) в другие, то что будет меняться (например нормативные акты) в третьи.
Ах, если бы еще в стартапах предметная область была сразу понятна и определена :)
Условный заказчик (он же как правило фаундер) не "не может определиться", а попросту еще не знает, как все будет выглядеть. Если знает - скорее всего мы просто кого-то копируем, а значит, что скорее всего уже не успели в рынок.
Как уважаемый @alex0x08 отметил тут:
Его еще нет даже в виде прототипа, концепция «плавает» а вам надо нанимать людей, развернуть всю инфраструктуру и поддерживать в виде критически важного начального этапа. И все это без больших бюджетов и с кучей постоянно возникающих проблем.
Чаще всего, в начале стартапа появляется достаточно хаотично написанный монолит с огромным кладбищем идей и гипотез (так как зачастую планы за один день меняются на 180 градусов, иногда и на все 360 - "Надо продавать онлайн курсы вместо холодильников! О, так мы уже? Ну и отлично!").
И уже потом, если бизнес внезапно выжил и идея оказалась как минимум не провальной, монолит потихоньку распиливают (или не потихоньку, если это копролит, который уже начал крошиться). Причем пилят не как удобно, а как оно лучше делится само. И что забавно, делится оно не всегда (например - то же Авито с PHP-монолитом, который распиливается, но до сих пор в каком-то виде присутствует)
Условный заказчик (он же как правило фаундер) не "не может определиться", а попросту еще не знает, как все будет выглядеть.
С таким подходом инвесторов не найдёшь.
Чаще всего, в начале стартапа появляется достаточно хаотично написанный монолит с огромным кладбищем идей и гипотез (так как зачастую планы за один день меняются на 180 градусов, иногда и на все 360 - "Надо продавать онлайн курсы вместо холодильников! О, так мы уже? Ну и отлично!")
Это норм. Как только с кодом быть? Весь выкинуть? Что-то переиспользовать? Переиспользовать весь монолит с зомби кодом?
Работал в стартапе, где большую часть фич можно было сделать изолированно. Накидал демку, задеплоил, показал клиенту, получил фидбэк в течении дня. Не зашло, удалил за пять минут. Сейчас на серверлес или на кубере такое можно за день сделать.
С таким подходом инвесторов не найдёшь.
А pre‑seed раунды на что придумали? :) Понятно, что сейчас за одну только идею денег никто не понесет (разве что если это какой‑нибудь очередной уникальный крипто‑AI, разработчики которого смогли в интеграцию с OpenAI и написание пары промптов), но в ковидные времена (кто же знал, что мы так скоро начнем по ним ностальгировать?) даже за простую идею на тему "что‑то связанное с удалёнкой" и макет в Фигме можно было собрать N‑ную сумму
Как только с кодом быть? Весь выкинуть? Что-то переиспользовать? Переиспользовать весь монолит с зомби кодом?
Что‑то выкинуть, что‑то переиспользовать. А то, что останется — ладно уж, пусть поживёт. И как показывает практика, это "оставшееся" переживёт еще многих людей в стартапе (бывает, что переживёт и сам стартап :) ). И как не менее уважаемый @SwingoPingo написал в посте:
Никто из всей цепочки от инвестора до Вашего непосредственного ни думал на такую дистанцию, все полезное что Ваш код должен был этим людям сделать (а это их бизнес) он уже сделал и себя окупил.
Накидал демку, задеплоил, показал клиенту, получил фидбэк в течении дня.
Это здорово, когда происходит именно так. Но иногда гипотеза живёт неделями (а то и месяцами), метрики расплывчатые, фидбэк неочевидный, и вместо быстрого удаления - несколько итераций, ресёрч, и только потом вывод - "не взлетело". Но безусловно, гигиену в коде никто не отменял.
И говоря про приоритеты:
на кубере
В стартапе (который обычно про скорость и гибкость), заниматься пляской с кубом вместо "херак и в продакшн" - звучит как попытка решить не ту задачу. Не всё, что масштабируется красиво, оправдано на ранней стадии. Хотя я как разработчик полностью согласен с тем, что упражняться в рисовании хелм чартов за деньги фаундера - это святое, однако это совсем не похоже на первую необходимость.
Что‑то выкинуть, что‑то переиспользовать. А то, что останется — ладно уж, пусть поживёт. И как показывает практика, это "оставшееся" переживёт еще многих людей в стартапе
Для этого надо дробить на модули, с чего мы и начали беседу.
В стартапе (который обычно про скорость и гибкость), заниматься пляской с кубом вместо "херак и в продакшн" - звучит как попытка решить не ту задачу.
Если есть экспертиза и кубер в облаках, то это и будет херак в продакшн. С автоматизацией в гитхабе автоматический деплой в прод делается легко. По сравнению с деплоем руками окупится на втором деплое. В стартапе, где я работал деплой занимал полдня и его мог сделать только один человек. Это было давно, сейчас технологии деплоя очень продвинулись.
Где же он живет - легендарный удобный для всех баланс между неудобствами от отсутствия правил и неудобствами от необходимости их соблюдения...
Слова вы правильные говорите, но вот как на пример "хорошего" кода посмотришь, так сомневаться начинаешь.
Аннотации отстутствуют.
Наименования функций совершенно не отражают их функциональность. Начиная с первых двух.
Если считать, что "хороший" код, это результат рефакторинга "плохого", так функция process_string возвращает list[int], который хоть и сортируется, как str, но в результат попадает как все тот же list[int], а в исходном варианте у вас там str.
Ну и выделять в функцию одну строку кода, это уже перебор.
Ну и выделять в функцию одну строку кода, это уже перебор.
Это норм. Вы так описываете бизнес логику. Умножение интов это низкоуровневая операция , а функция уже уровнем выше.
Если бы это был класс, от которого можно было бы отнаследоваться, или если бы две первые функции были методами другого класса, передаваемого, как параметр в данный, тогда да, а так неоправданное усложнение. Тогда, кстати и к именам претензии бы не было.
Если можно обойтись функцией, то класс это усложнение.
Если можно обойтись функцией, то класс это усложнение.
По индукции: если можно обойтись строкой кода, то единожды вызываемая функция тоже усложнение :)
Функции и классы они переносят код в более высокий домен. Вы не считаете сколько там заглавных букв в строке, вы валидируете ввод пользователя согласно бизнес требованиям. Когда я читаю код с бизнес логикой, я не хочу отвлекаться на низкоуровневые операции, так как смена контекста требует ресурсов. Я хочу глубоко и качественно погрузиться в проблему, затратив минимум времени.
я не хочу отвлекаться на низкоуровневые операции
1
Я хочу глубоко и качественно погрузиться в проблему
Как-то два ваших высказывания немного противоречат друг другу. И где в обсуждаемом примере бизнес-требования/логика и где низкоуровневые операции, я плохо понимаю. Вот если бы первые две функции вызывались хотя бы в паре мест. Вот как только, так сразу, а пока нет.
process_string это бизнес логика мы конвертируем строку в набор цифр. Зачем-то бизнесу так надо. Это могут быть не совсем прямые требования от бизнеса, а результат декомпозиции задачи лидом.
Внутри какие-то операции с байтами, это низкоуровневые операции, бизнесу не важно, что том делается, важен результат.
Поддержу. Пишу основной модуль в декларативном стиле бизнес логики как будто я начальник и даю непосредственные указания подчинённым. А уж декларации потом в отдельных функциях императивно выполняю. Это даёт самозадокументированный код и описание бизнес-процесса на момент реализации, а его у заказчика никогда не бывает и позволяет избавиться следующим от адских реверс инженерингов. Правда следующие обычно ×ерят всю структуру потому что так просто вставить одну строку императива, да?
К сожалению декларативный подход сильно недооценивают.
Хотя он дает кучу преимуществ. Особенно в сопровождении.
А какая польза для дообучения моделей!
Готовые пары "что сделать" - > "как сделать".
Там по идее следующий этап зрелости деклараций это законченные проверямые результаты в бизнес-объектах после каждого оператора.
Тогда на модуль, вызывающий ошибки можно будет выходить прям со слов пользователя в его терминологии.
Правда будем терять в производительности от этих "сериализаций данных в бизнес-объекты".
Может грамотные компиляторы разошьют этот искусственный уровень без подъема данных памяти до уровня бизнес-абстракций в продуктивной среде и с этим подъемом в среде разработки со временем.
Мои лучшие функции были однострочными :) Усердно практикуйтесь несколько лет и Вы познаете истину.
Это вайбрайтинг про вайбкодинг. С нейрогалюцинациями лучше не спорить, если не хотите получить очередную порцию, как выше.
Иронично, что буквально недавно была хорошая статья в этом же блоге про новшества в аннотациях питона: https://habr.com/ru/companies/ruvds/articles/905832/
Спасибо за ссылку на исследование. Любопытно как авторы пытаются дать определения "чистому коду" или измерить читаемость аж 8 математическими методами. Склонен считать, что лучше всего получилось у Ann Campbell с ее метрикой "cognitive complexity". Хотя "сложность" (машинную) и "трудность" (человеческую) часто путают и смешивают.
Хочется верить, дедлайны - это основная причина говнокода, но у меня на проекте это точно не так.
Проект начинался в режиме стартапа с очень ограниченными временными и трудовыми ресурсами. Мы работали быстро и делали много. Оценка задачам давалась с квантованием в 30 минут. Как уж тут без говнокода...
Прошло 11 лет. Народу на проекте стало больше. Начальство сменилось на разных уровнях более чем по 3 раза. Никто уже не требует былых темпов, да и не осталось никого из тех, кто помнит, как тут было принято работать раньше. Квантование оценки задачи - день. Ничего с нуля придумывать почти никогда не надо. Еще одна кнопка, еще одна форма, еще один HTTP API. Работа - не бей лежачего. Думаете, стало говнокода меньше? Нет. Только через code review и спасаемся.
79% респондентов указали, что основным барьером является нехватка времени из-за жёстких дедлайнов
Если бы опрос провели на моем проекте, я бы таким результатам не поверил. Люди пишут говнокод потому что или не могут отрефлексировать, или надеются, что code review будет выполнять не очень бдительный коллега.
А если так?

У всех понятные названия и лаконичные docstrings. Такой код читается без напряжения
Автору на заметку. "Читаемость" функции означает в том числе и то, что в месте использования то, что делает функция, понятно без необходимости лезть во внутренности.
В "первом абстрактном" примере кода внутренности функций неявно текут за границы файла: название process_something мне не говорит ровным счётом ничего, и, чтобы разобраться, что происходит и какую задачу решает функция, мне придётся залезть внутрь или наводить курсор на метод с надеждой, что вылезет окно с документацией.
Итого, чтобы понять код на более высоком уровне абстракции, мне нужно будет держать в голове документацию на все используемые методы. В контексте цитаты сверху я это назову "чтение с напряжением". К примеру, название multiplyByTwo выдаёт детали реализации, но в месте использования хотя бы понятно, что происходит.
В целом стиль статьи сочту "неинженерным" от слова совсем: аргументация недалеко уходит от "я так примерно почувствовал". Про измеряемые характеристики кода можно почитать, к примеру, в "Чистой архитектуре" Мартина: входящие/исходящие завивимости, устойчивость, абстрактность. В книге "Фундаментальный подход к программной архитектуре" Марка Ричардса и Нила Форда дополнительно можно почитать про коннасценцию различных видов.
В данном контексте именно такие имена, как у автора, подходят лучше. Оно говорит нам не «здесь нужно число умножить на 2» (почему? почему именно на 2? это требование алгоритма?), а «здесь нужно обработать число некоторым способом в соответствии с тех.заданием, какое бы оно ни было». В данном случае это умножение на 2; было бы другое требование — реализовали бы другой алгоритм.
Спасибо за комментарий. Наводит на мысль, что факт того, что название функции мной и вами интерпретируется по разному, и назначение функции надо додумывать, говорит не в пользу качества этого названия. Полагаю, приведённая вами формулировка (отсутствующая в статье и коде примера) прекрасно бы выразилась в названии "somehow_process_number".
Я уже писал. Тогда нужно было делать класс, чтобы или от него отнаследоваться, или операции с элементами списка выносить в другой класс.
Данный контекст ограничивается кодом, который мы видим. Это законченная программа. И вы этой законченной программе число умножается именно на 2.
Кроме всего прочего, к сожалению, глаз замыливается.
Когда долго копаешься в каком-то куске кода, глаз видит то, что в этом коде имелось ввиду. А не то, что на самом деле написано.
Поэтому да, можно вооружиться всякими хорошими добрыми принципами, сесть, и написать идеальный код. Но когда через полгодика на него посмотришь, не факт, что он будет казаться всё таким же идеальным, как в первый раз...
Хотел добавить но нервы не выдерживают когда стал вспоминать сколько дерьма за консалтингом разгреб.
Это ребята шурупы вколачивают а гвозди вкручивают...
Я как-то работал в одной конторе, которая делала WiFi чип (и, к сожалению, не сделала. В смысле, не довела до товарного вида).
Начинал я с ними, как контрактор, и написал по контракту линуксный драйвер ихнего WiFi чипа. Для венды у них какой-то драйвер был, но такой, они не рассчитывали вывести его в production.
Меня тем временем взяли в штат, а для венды заказали у третьесторонней конторы драйвер промышленного качества. И дали им мой линуксный драйвер, ну, просто в качестве документации.
Потом от них пришел результат. В общем, вместо того, чтобы написать нормальный вендовый драйвер, они решили мой под венду перенести. Проблема в том, что в линуксе, в ядре, почти всё, что приходит к драйверу, приходит на контексте какого-нибудь процесса (что примерно соответствует IRQL = PASSIVE_LEVEL в виндовсной терминологии). Т.е., можно использовать мьютексы, примитивы ожидания и т.п. И я этим активно пользовался. А в венде практически все обращения к драйверу идут на контексте, который в венде называется IRQL = DISPATCH_LEVEL, и примерно соответствует линуксному interrupt bottom half. И блокироваться там нельзя от слова совсем. А они этого совсем-совсем не понимали.
В общем, когда я посмотрел, что они с моим драйвером сделали, у меня немного глаза на лоб полезли. Нанесли моему несчастному коду тяжкие телесные повреждения. Где-то синхронизацию отломали вовсе, где-то заменили ее спин-локами, посыпались assert-ы, их тоже заглушили. Ужос, одним словом.
Пришлось потом очень долго за ними это разгребать.
неплохо.
У меня был проект в начале 2000x, flow engine.
Я тогда писал редактор для него, а один китаец серверную часть для редактора.
По тому времени все было неплохо, SVG графика, редактируемые примитивы, правила соединения узлов графа, все короче абстрактно и абсолютно переносимо куда угодно. UML редактор практически
Начинаем сдавать давать работу - не работает. Смотрю код серверной части - сделано ровно то что требуется для одного маленького юнит теста... В общем схема из трех элементов и жесткий парсер под нее. Почти дошло до рукоприкладства , китаец обиделся , руководство китайца поддержало ( в Канаде морды бить не принято).
Софт скилы у китайца были прокачаны - головорил плохо но писал изумительно, начальству в глаза заглядывал как кот из Шрека.
В общем ставят его лидом. И лают проект для дилершипов Тойота для всей Канады, по всем провинциям.
Делаем ПоС.
Я пилю управлялку для фермы виртуалок на VMware и обвязку на Винде на c# под IE host - ну а внешнее приложение управляет фермой IE браузеров. Еще пару человек работало над ПоС.
В ладоши похлопали, пос прошел. Потом вдруг заданий от лида нет, 3 месяца пишу в отчетах "самоподготовка". Всем пофиг, я читаю книжки по VHDL/Verilog, игрался тогда с FPGA Xilinx.
В конце срока прибегает владелец конторы с красной мордой - а где результат? Китаец говорит что едет в Шанхай, проект идет в унитаз. Тойота делает сеппуку (нам).В Шанхае он запрыгивает на менеджерскую позицию в AT&T.
Я еще годик добил в этой конторе и ушел.
Вывод - софт скилы рулят :)
Однозначно.
Лошадь работает больше всех но почему то она не председатель колхоза.
С другой стороны, там где рулят только софтскилз, бизнесу приходит каюк.
С другой стороны бизнес не ваш и его судьба должна волновать других.
все верно.
Чуть позже открыл свою корпорацию и перешел на контрактную работу. 18 лет она прожила, только в 2022м закрыл в январе. Контрактником быть выгоднее если ты активен.
Тот же владелец потом вызывал, летал к нему на проекты. Вылетел как то в мае на пару недель, и закрутилось... Вернулся к новому году. Торонто Пирсон аэропорт пару проектов выполнил - один по автоматизации работ персоналом, другой для такси лимузинов точка самообслуживания.
Попутно освоил бухгалтерию, года через 3, как глянул что бухгалтер пишет которого на аутсорсе нанимал, и начал вести ее сам, в quickbooks. Иначе понял что сяду если его отчеты проверят
Но когда через полгодика на него посмотришь, не факт, что он будет казаться всё таким же идеальным, как в первый раз...
Через полгода, вы узнаете больше о проекте, о процессах разработки и технологиях. Ваши стандарты станут выше.
вспомнился один проект... Ставили кастомизированный, если память не подводит, radius сервер у провайдера спутникового ТВ. Программка через спутниковый канал подмешивала инструкции для приемника тв какие передачи записать. А звонили клиенты по dial up, чтобы инструкции передать, провайдеру тв. OpenTV и сеттап боксы то еще убожество были, ansi c в чистом виде, многих привычных функций нет, отладка по шнурку, десяток моделей, у самой слабой меньше мега памяти... Шел 2003й год.
Отвлекся. Так вот, взяли проект радиуса в котором код "был как персик", на 5± но документация дрянная - его подрехтовали. Заказчику же слили документацию с другого опенсорс радиуса, у которого документация "была как персик" а код смотреть невозможно, спагетти.
Как до Мартина программировали и системы строили - загадка)))
С осторожностью и пониманием, что если когда программируешь, не думать, придется в 10 раз больше думать, когда отлаживаешь
Также. Он не придумал ничего нового, кроме названий.
А во времена «до Мартина» было допустимо воздействовать невербально на коллег, которые пишут говнокод и тащат отовсюду блоки без оглядки на заложенную в данный проект архитектуру, превращая всё в своей зоне ответственности в свалку. 😁
Проблемы, которые описывает Дядюшка Боб, существуют много лет, и было много предложений по их решению.
Забавно, что про книги говорят иногда так, как будто до публикаций Роберта Мартина были «тёмные века разработки».
Конечно же, это не так. Вот, например, статья 20-летней давности в «Открытых системах», которая даёт ретроспективу:
https://www.osp.ru/os/2006/03/1156577
В общем-то, она так и называется: «Ретроспектива программных архитектур».
27.04.2006, Филипп Крачтен, Хенк Оббинк, Джудит Стаффорд.
Чистый код — красивая архитектура. А работает ли это?
Да, работает, если на проекте трудятся люди, которые знают, что это такое и зачем оно нужно.
Если на проекте есть и другие люди - то их зону ответственности нужно изолировать таким образом, чтоб у них не было шансов нарушить общую архитектуру, чтоб их нечистый код был только их проблемой.
Это и есть главная задача архитектуры, разбить код на независимые кусочки и поставить между ними контракты. Тогда можно совмещать в системе мудули с разным качеством и переписывать их по мере надобности.
Другие люди обычно ленивые в плане разработки. Поэтому они начинают пользоваться выработанными паттернами, если они конечно есть. Это позволяет копипастом, сильно не думая, писать.
Зачастую , проблема в том, что "все и сразу" продумать не получается. И дело тут не только в компетентности разработчиков, а скорее, даже больше, в "адекватности" клиента и его требований. Все эти DDD, и там баундед контексты хороши только в первые год-два разработки и эксплуатации продукта, но потом текучка сотрудников как у клиента, так и у разработчиков, а так же "текучка" требований просто постепенно смывает все это DDD и все эти контексты в унитаз.
Я не говорю, что это все плохо, и у меня нет ответа как сделать лучше. Просто делюсь мыслями.
Может быть как-то создавать конструируемые объекты,чтобы потом проще было их разбирать и пересобирать? Потому что что-то переделывать всё равно придется и не раз.
У меня давно возникло стойкое ощущение, что Liskov Substitution Principle (LSP) никто не знает, никто нормальным языком не может это объяснить (а лучше ещё и на примерах).
Это при том, что это один из самых простых и однозначных принципов.
Ну это же довольно простая концепция. Не ломать об колено в наследниках фичи, определенные в базовом классе. Наследники могут расширять функциональность, но им запрещено изменять семантику обязанностей базового класса или интерфейса. И тогда, мы смело можем использовать наследников и имплементоров, в тех же сценариях, где их предки успешно работали.
Например, для базового класса такси - наследниками могут быть седаны, минивэны, пикапы и прочие авто, может быть бензин, дизель, газ или электро, может быть руль справа или слева, мы все равно получим то, что ожидаем от такси. Но если от такси унаследовать велик или самокат, то будет трабл.
Ну или например, если от иммутабельного квадрата наследовать иммутабельный рямоугольник - это будет трэш. А в другую сторону - норм.
То есть потомки не должны радикально менять свою ДНК, только некоторые признаки могут мутировать.
Батенька, ну что Вы такое говорите. Зачем седан от такси наследовать-то? Вот Вы сами посудите :) Я здесь один Ваш комментарий прочитал. Думаю, какие умные вещи человек пишет. А здесь такой эпик фэйл.
Зачем седан от такси наследовать-то?
А как правильно?
Андрей, я не знаю. Зависит от контекста. В нашем деле абстрактного "правильно" не существует. Существует только "неправильно" и то с некторой вероятностью. Я бы ООП не увлекался вообще. Использую реализацию ООП в языке для реализации паттернов того или иного уровня. Например, наследование в большинстве случаев для полиморфного поведения. Например, для template method.
Можно начать с простого. Сделать "седан" строковым полем в классе такси.
Можно начать с простого. Сделать "седан" строковым полем в классе такси.
Так седан тащит за собой кучу логики, цена на мойку, заправка. У электрического миневена будет по другому. А у роботакси не будет водителя. Строкой не выйдет.
Для классов стандартной библиотеки, стоит выбирать композицию, а вот для собственных, можно и наследовать, особенно если они для этого дизайнились.
Предпочитаю не фантазировать. В каждой точке исхожу из того, что известно. Если будет роботакси, будет рефакторинг, перед внесением изменений.
Если надо цена, то можно создавть по строке "седан" CostStrategy или CostAlgorithm.
Строка, это самое простое, с чего можно начать. Дальше уже по ситуации действовать.
Это проблема абстрактных задач. Всегда можно подогнать условие под решение. Я бы только начал с энума, чтобы валидировать при создании, а не при использовании.
Тут на примере показано, что с ним не так: https://page.hyoo.ru/#!=dynrai_6jc0xi
Ну там же голословная демагогия, замешанная на манипулировании понятиями типа и интерфейса. Вариантность - это чисто формальная языковая хрень. Полезный, но сугубо формальный инструмент. Он не заменяет поведенческих контрактов, а лишь иногда помогает их типобезопасно выразить. А фундаментальные принципы системного дизайна, и архитектурные, и, как в случае с ЛСП, поведенческие - они же универсальны и не завясят от конкретных средств имплементации.
ЛСП сформулирован давно, на легаси-языке "типов", еще до вызревания современных концепций ООП контрактов, интерфейсов и протоколов, и его суть - не во втискивании реализации в формальные ограничения языков, а в проектировании поведения системы объектов таким образом, чтобы каждый объект, реализующий какой-то интерфейс, независимо от конкретного типа этого объекта, гарантировал и строго соблюдал существенную семантику обязанностей и ответственности этого интерфейса.
Недостатки любых абстрактных систем при желании можно всегда найти и набросать на вентилятор - теорема Гёделя о неполноте в помощь. 😁
Но если мы верим в фундаментальные принципы, а иного способа легализовать их не существует (как завещал великий Гёдель), то мы обязаны их соблюдать полностью. Иначе это будет другая вера.
Так что реальное соблюдение ЛСП - это проектирование контрактов и тестирование инвариантов. И делаться это должно не ad hoc, в процессе кодинга, а на этапе анализа и проектирования системы.
В конце концов, ЛСП - это же не про заклинания и магию языковых фич, а только про здравый смысл.
А здравый смысл нужно беречь.
Когда убеждения сталкиваются с реальностью, начинается словоблудие.
Про Гёделя, кстати, можете почитать тут: https://page.hyoo.ru/#!=ixy44o_3oga48
Да и статью про вариантность в современных языках зря скипнули: https://page.hyoo.ru/#!=3skw_ac25gk
Хех.
Ваше заявление про словоблудие - агрессивный эмоциональный ярлык без фактов.
Ваша ссылка на якобы опровержение теоремы Гёделя не указывает на ошибки в его формальных леммах.
Ваш длинный текст про вариантность может быть и полезен, но он не доказывает, что сама вариантность равна ЛСП, он лишь рассказывает про правила подстановки типов.
Мы же с вами обсуждаем поведенческие контракты, инварианты, предусловия и постусловия, про которые формальная языческая (всм языковая, но беспринципная) вариантность вообще не в курсе.
Можно, наверное посмотреть ваши примеры кода, где вариантность нарушает ЛСП, если имеются. Но мне кажется, что вы уже провоцируете холивар. А сейчас наступает время перемирий. Так что я прекращаю огонь. 🔫✌️
Если бы вы потратили на чтение предложенных статей больше времени, чем на написание своего комментария, то не написали бы столь концентрированной чуши. Примеры кода там тоже есть, скорострел вы наш.
Ваша статья про первую теорему Геделя о неполноте демонстрирует, что вы не поняли даже формулировку этой теоремы.
Гедель утверждает существование формулы в арифметике, которую нельзя ни доказать, ни опровергнуть.
А у вас арифметика превратилась в "любую непротиворечивую систему утверждений" - с этим и сам Гедель не согласен в свой теореме о полноте классической логики, в которой множество тавтологий вообще-то тоже - непротиворечивая система утверждений.
И еще "невозможность опровергнуть" с какого-то перепугу превратилась в "правдивость". Для справедливости такой замены сначала надо доказать полноту. Вот для классической логики эту полноту Гедель доказал, там можно ставить знак равенства между неопровержимостью и истинностью. А в арифметике - нельзя. Тоже Гедель доказал.
Поэтому опровергаете вы там что угодно, но не теорему Геделя.
Мне было лень писать вам ответ, поэтому держите дипсик - даже он больше в теме, чем вы:
Распиши фактологические ошибки в понимании критиком теоремы Гёделя о неполноте.
Автор комментария допускает несколько фактологических ошибок в понимании первой теоремы Гёделя о неполноте. Разберём их по пунктам:
1. О неверном расширении области применимости теоремы
Автор пишет:
"А у вас арифметика превратилась в 'любую непротиворечивую систему утверждений'".
Ошибка:
Первая теорема Гёделя действительно формулируется для достаточно богатых формальных систем, способных выражать арифметику (например, арифметика Пеано или ZFC). Однако её часто обобщают на другие системы, удовлетворяющие ключевым условиям:
Рекурсивная аксиоматизируемость (аксиомы можно перечислить алгоритмически).
Достаточная выразительная сила (возможность формализовать базовую арифметику).
Это не означает "любую непротиворечивую систему", но и не ограничивается только арифметикой. Например, теорема применима к некоторым системам теории множеств или теориям второго порядка.
2. О путанице между теоремами Гёделя
Автор противопоставляет:
"с этим и сам Гедель не согласен в свой теореме о полноте классической логики".
Ошибка:
Здесь смешиваются две разные теоремы:
Теорема о полноте (1929): В классической логике первого порядка формула истинна во всех моделях тогда и только тогда, когда она выводима из аксиом. Это относится к логической истинности, а не к арифметике.
Теорема о неполноте (1931): В достаточно сильных арифметических системах существуют формулы, которые нельзя ни доказать, ни опровергнуть. Это относится к формальной недоказуемости.
Автор ошибочно использует полноту логики для критики неполноты арифметики, хотя эти теоремы говорят о разном.
3. О подмене "неопровержимости" на "истинность"
Автор утверждает:
"И еще 'невозможность опровергнуть' с какого-то перепугу превратилась в 'правдивость'".
Контекст:
В доказательстве Гёделя строится формула G, которая в неформальной интерпретации гласит: "Я недоказуема в данной системе". Если система непротиворечива, то G действительно нельзя доказать, а значит, она истинна (поскольку утверждает свою недоказуемость).
Нюанс:
Да, строго говоря, "истинность" здесь — это семантическое понятие, относящееся к стандартной модели арифметики, а не к синтаксической неопровержимости. Однако в конкретном случае гёделевской формулы G эти понятия совпадают, так как G построена так, чтобы быть истинной, но недоказуемой.
4. О полноте арифметики
Автор пишет:
"Вот для классической логики эту полноту Гедель доказал, там можно ставить знак равенства между неопровержимостью и истинностью. А в арифметике - нельзя".
Ошибка:
Это верно для логики первого порядка, но не для арифметики. Однако автор упускает ключевой момент: в теореме о неполноте речь идёт не о произвольных формулах, а о конкретной G, которая семантически истинна, если система непротиворечива.
Таким образом, замена "неопровержимости" на "истинность" для G корректна, но не для всех формул арифметики.
Итог: основные ошибки автора
Сужение области применимости теоремы только до арифметики, хотя она работает для многих формальных систем.
Путаница между теоремой о полноте логики и теоремой о неполноте арифметики.
Непонимание специфики гёделевской формулы G, которая одновременно недоказуема и истинна (в стандартной модели).
Игнорирование семантического аспекта: для G истинность действительно следует из недоказуемости в непротиворечивой системе.
Теорема Гёделя действительно требует аккуратного изложения, но критикующий сам допустил серьёзные неточности в её интерпретации.
Такой наглости я еще не встречал :) Аппелировать к стохастически порожденным текстам в споре о точных вещах.
"Гедель утверждает существование формулы в арифметике, которую нельзя ни доказать, ни опровергнуть." - это абсолютно точное утверждение, являющееся частным случаем теоремы, которого мне достаточно, чтобы опровергнуть ваше якобы доказательство.
Остальное фуфло от дипсика разбирать лень. Всего хорошего.
Тот случай, когда глупая нейронка порождает куда более осмысленные и связные тексты, чем очередной хабра-опровергатель.
Подсказка
В моей статье основной посыл не в доказательстве чего бы то ни было, а в разоблачении трюка, на котором построены известные софизмы, породившие громкие выводы и расколовшие математиков на два непримиримых лагеря: интуитивно чувствующих подвох, и фанатично верующих в небылицы.
Хе хе. Про наглость забавно.
Для дилетантов, посмотревших несколько видосиков, и познавших кайф от осознания своего всемогущества после запуска хелловорлда, все эти философские рассуждения - набор знакомых, но непонятных слов.
Для того, чтобы делать красиво, нужна лишь мощная внутренняя мотивация, потребность в удовлетворении чувства прекрасного, неустранимый зуд перфекционизма. И тогда ты начинаешь общаться со своими объектами по именам, которые ты им заботливо придумываешь, как своим детям, стараешься не переутомлять их лишними разнообразными обязанностями, справедливо их распределяя между всеми участниками этой эпопеи, сюжетные линии, сценарии и диалоги которой ты уже досконально продумал, как Гомер свою Илиаду и Одиссею, и тебе остаётся только всё это записать понятным литературным языком программирования, чтобы твою поэму было интересно и легко читать, и чтобы читатели были в восторге от твоего мастерства владения словом, в таком же, как от чтения Мёртвых душ Гоголя, когда читаешь фразу, кайфуешь от её звучания, и ловишь себя на мысли, что ещё не дочитав её, хочешь поскорее схватить глазами следующую.
Так что ничего тут нового не откроешь. Как и в литературе, есть настоящие поэты, а есть рифмоплеты и графоманы, так и в программировании - есть истинные мастера, и есть авторитетные говнокодеры. И мастерство это определяют не звания, дипломы и должности. Это внутреннее состояние души. Это не рациональные рассуждения, а трансцендентальное стремление к совершенству, независимо от величины тарифной ставки и социального статуса.
Вся эта теория в момент разбивается о практику, когда тебе вместо того чтобы всего лишь взять и тупо сверху донизу прочитать за пять минут тупую "простыню" кода, приходится по полдня скакать туда-сюда по трем десяткам методов в одну-две строчки каждый, которые еще и вызывают друг друга с десятком уровней вложения, и которые раскиданы равномерно по всему проекту - методов на которые какой-то очередной упоротый "чистокодник" исходную "простыню" разбил (или как там красиво надо говорить - "декомпозировал").
Хуже этого только когда еще в разных местах делают утилитарные методы с одинаковыми названиями, но разным поведением. Да и названия тоже могут не блистать прозрачностью: String isGetSetAndGo() --- вот такой замечательный метод запомнился из моей практики.
Я недавно видел у нас проекте лютый треш
if (BooleanUtils.isNotTrue(mandatory))
вот где ужас
Простите, а в чем проблема? Возможно вот так лучше, если Вы автоматически такой паттерн улавливаете.
if (!BooleanUtils.isTrue(mandatory))
Проблема в том, что в этом коде имелось в виду
if (!mandatory)
но вместо того чтобы прям так и написать в программе, был придуман какой-то очень сложный способ, какой-то совершенно ненужный -utils. Ненужное усложнение совершенно простых вещей - в этом проблема
Что будет, если mandatory = null
?
Или Вы просто шутите?
Очевидно нет, не шучу, ни одного смайлика не поставил :-)
А чтобы mandatory не было null надо просто сделать его примитивным типом boolean. А если оно не указано (в конфигурации или в запросе) то присваивать ему значение по-умолчанию. Которое всегда есть, но оно либо зашито глубоко в BooleanUtils либо сразу и очевидно присваивается из конфигурации
У Вас null может с базы прийти или с HTTP запроса. На этом уровне BooleanUtils лучше работает, чем значение по-умолчанию. Далее, конечно, лучше boolean везде по коду использовать, с обычной проверкой if (!mandatory)
Я такие конструкции if (!BooleanUtils.isTrue(mandatory)
не использую. Добавляю вспомогательный метод boolean getManadatoryCorrected()
на уровне модели.
Хуже этого только когда еще в разных местах делают утилитарные методы с одинаковыми названиями, но разным поведением.
В некоторых языках ещё ничего, а в Питоне порой IDE не может даже найти где они объявлены. Я стараюсь методам выставлять видимость только на уровне модуля, тогда конфликтов поменьше.
Уважаемый Принц Коровин. По-другому не получится. Не получится бесплатно получить постоянную скорость внесения изменений. Я давно этим вопросом интересуюсь. Это единственный способ.
@VladimirLadynev, для упоминания людей есть специальный синтакс, используйте пожалуйста его. Вольная интерпретация имён режет глаз.
Это, в первую очередь, не для чтения, а для внесения изменений. К сожалению, в нашей науке ничего лучшего не существует. С простынями более серьезные проблемы возникают.
Вы сравнивает хорошую простынь, с плохим разбиением.
А вот в плохой простыне нужно будет поскролить пол страницы вверх, чтобы понять, где эта переменная менялась.
Вы как читаете дерево условных операторов в глубину или ширину?
Думаете в методах на 1000 строк не приходится скакать туда сюда по вызванным функциям?
Хорошее разбиение оно по уровню логики, читаешь сначала верхний уровень, потом углубляешся в каждую функцию по очереди. Получается дерево, ветки которого не переплетены. Ближе к листьям начинают появляться вызовы общих библиотек.
Андрей, такое впечатление, что Вы меня разыгрываете. Вы эти вопросы серьезно задаете?
Я целиком и полностью за чистоту и кода, и архитектуры, и SOLID, и паттерны. Но, чтобы это нормально применять необходимо наличие достаточного ума, компетентности, и квалификации. Чего у говнокодера, которым давно уже является среднестатистический "погроммист" типа упомянутого выше isGetSetAndGo
и в помине нет. А наплодить стопиццот однострочных методов может любая обезьяна из зоопарка - вот эти методы и плодятся.
Взять пример автора с его process_blablabla
. Если бы ситуация была более сложная, заслуживающая того чтобы всё это как-то разбить на части и структурировать, то я, например, сразу подумал бы сделать это через "visitor". А если просто разбивать на кучу методов, то любая ветвистая "простыня" так и остаётся "простынёй", только размазанной по сотне разных мест, от чего становится ещё хуже для восприятия.
очередная статья за все хорошее против всего плохого, может закончим порожняк гнать и четко определимся в чем чистоту измеряем, в каких величинах? допустим codestyle смогли настроить - дальше что? конкретные критерии, которые не зависят от погоды на марсе
а то известно чем заканчивается когда появился тимлид у которого 7 пятниц на неделе, сегодня ему нравится одно завтра другое, а проект в итоге весь из шизоидных лоскутов сляпан
Нет таких критериев. Те критерии, которые описаны на данный момент, можно использовать для внесения изменений, чтобы понимать в каких направлениях делать рефакторинги. Критериев, которые подходят для оценки чистоты, похоже, не существует.
То на что можно ориентироваться:
Одинаковое форматирование кода. Автоматизируется легко.
Стайл проверки инструментами. Не всё можно автоматизировать, но улучшение качества кода заметное.
Цикломатическая/когнитивная сложность. Они достаточно похожи можно выбрать одну. Легко автоматизируется.
Тестовое покрытие. Только не надо средне по палате мерить, для разных частей системы разные требования. Ну и смотреть стоит на изменение, а не на сами проценты.
Командные процессы, например ревью кода. Если другой человек смог прочитать ваш код и понять, то возможно он чистый.
Это не сделает ваш проект чистым, но много грязи отсеет до попадания в кодовую базу. Входной порог не нулевой, но потом уже не требует много усилий для поддержки.
кодестайл - принимаем
цикломатическая/когнитивная сложность - принимаем
coverage - тоже ок
ревью - не годится, не измеримая метрика, субъективщина
если человек прочитал - не годится. давайте без "если" и без "человека" - сегодня он в настроении, а завтра нет
если человек прочитал - не годится. давайте без "если" и без "человека" - сегодня он в настроении, а завтра нет
Просто наличие ревью уже влияет на поведение пишущего код.
Без человека это ИИ. Пока попытки были не успешными.
Автоформатирование не принимаем, ибо зачастую оно ухудшает читаемость. И дело даже не столько в том, что большинство кодстайлов фиксировали по принципу "я так привык и вы должны писать так же", а не "так будет лучше для всех потому что", а в том, что эти правила обычно слишком примитивные, чтобы учесть все особенности восприятия человеком. Теоретически тут могла бы помочь нейронка, если бы её обучали на хорошо отформатированных кодах, но её обучали на чём попало.
Когниматические сложности не принимаем, ибо они дают простые, но ложные направления изменения кода, где борьба идёт с мельницами (вложенными блоками кода), а не драконами (кодом, который требует повышенной концентрации для понимания).
Покрытие не принимаем, ибо не любой код нуждается в тестировании вообще благодаря статической типизации, а некоторый код нуждается в тестировании на 500% из-за множества граничных условий, никак не связанных ни со строками текста, ни с условными ветвлениями.
еще раз этот тред про метрики "чистоты" кода.
если вы говорите про читаемость то дайте измеримый критерий, через который эту читаемость можно выразить.
пока что вы в анархическом стиле отвергли все правила, не предложив ничего взамен. а вот теперь представьте ситуацию над проектом работаете вы, тимлид и Васька-говнокодер. тимлид кореш Васяна и он ставит ему апрув не глядя, а в ваших коммитах доебется до каждой буковки. вы к чему апеллировать будете в этой ситуации, к каким объективным метрикам?
Как тимлид, я не докапываюсь до буковок и делегирую ответственность. Моя задача помочь человеку подсветить проблемы, которые он не заметил, а не продавить свои привычки. А то что вы описали называется вахтёр.
вы на вопрос по существу не ответили. опять про какие-то абстрактные проблемы. а я скажу что проблем нет. чем докажете обратное?
Пару раз у нас качественным критерием "подешел/не подешел" было мнение всей команды. Но это когда уже так не подошел, что ни в какие ворота. Обычно Вася то говнокодит, но допустим неплохо администрит БД и вообще выходит работать на всякие факапы или чувство юмора прекрасное имеет, за что его команда и любит.
возможно Вася начудил не со зла и уверен что его код "чистый", а вам нечего возразить, потому что нет четких критериев
мнение всей команды
но мнение команды это мнение N людей. люди сегодня в хорошем настроении и говорят одно, завтра в плохом настроении скажут абсолютно противоположное, поэтому полагаться можно только на автоматизированные проверки
Человек мерило всех вещей! Вот мне сегодня туфли прям подошли, а завтра уже маленькие или не модные или настроение не то, так что ж мне теперь.
Даже так скажу. Вот мы с Вами задумались над качеством кода и даже больше, над количественными параметрами качества и даже автоматизированными проверками этих параметров. И мы с Вами уже в топ-10% продукта. (А может и в топе 5% даже)
Потому что статьи такие пишут когда влазат в код из лоу 10% от острого чувства отчаяния. Правила вообще все придумывают для жлобов, которые вообще плевать хотели на все человеческое и прижучить их нельзя потому что скользкие как ужи и "а где это написано?".
Людям же не соответствие написанному нужно, куда как более простое ТЗ никто составить не может, им нужно что бы проблемы их решались хотя бы в нужном направлении, можно даже не полностью.
У меня есть субьективный критерий читаймости: насколько человек боится вносить изменение в код, которые он до этого писал. Величину "боится" примерно видно по вносимым изменениям. Это субъективно, конечно.
Покрытие не принимаем, ибо не любой код нуждается в тестировании вообще благодаря статической типизации
Особенно в языках, где строка может быть строкой, null или undefined.
По остальным вопросам лень спорить, вы начинаете спамить ссылками, которые я зарёкся открывать. Просто останемся с разными мнениями.
Вы с такими подходами PCI Compliance не пройдете. Причем, не обязательно Ваш текущий проект должен быть связан с PCI. Достаточно, что у организации есть такая связь.
А что там в этом в этом PCI такого?
Есть требования по код-ревью и по юнит тестам. Причем это все быстро через тот же GitHub проверяется. Вы прямо в master комитите, или черз пул реквесты.
Можно пример таких требований? И какое отношение мой закрытый код имеет к социальной сети для оупенсорсеров?
GitHub это стандарт корпоративного репозитория, а не социальная сеть для опенсорсеров. Так же как и google приложения.
Один из примеров — нельзя коммитить в master. Должен быть пул реквест, который должен быть заапрувлен одинм или несколькими уполномоченными на это людьми. Даже если у Вас проект к PCI зоне вообще не имеет отношения.
Мне ещё и гуглу надо все свои пуиватные данные отдавать? Вот это новость.
А какое отношение правила работы с ветками имеют к метрикам кода?
Покрытие не принимаем, ибо не любой код нуждается в тестировании вообще благодаря статической типизации, а некоторый код нуждается в тестировании на 500% из-за множества граничных условий, никак не связанных ни со строками текста, ни с условными ветвлениями.
Я по поводу этого сказал, что это может PCI Compliance противоречить.
Работа с ветками это пример требования PCI Compliance, который Вы меня попросили привести.
Мне ещё и гуглу надо все свои пуиватные данные отдавать? Вот это новость.
Да. Если Вы хотите работать в комфортной корпоративной среде. Лучше Google отдавать, чем какому-нибудь VK, например.
Не торчите в абстрактных дуальностях, это мышление убогое и оторванное. Как вариант, ко всем категориям приписывайте "достаточно". Это будет заставлять вас думать про реальный контекст, всякий раз говоря, например, "достаточно хорошо ДЛЯ ..."!
Чистый код — красивая архитектура. А работает ли это?