Мартин Шлейс (Martin Schleiss) попытался сравнить различные открытые проекты с точки зрения усложнённости кода и понимания как код работает и какие действия выполняет. Например, проект становится более сложен для понимания при применении сложных абстракций, таких как распределённое взаимодействие компонентов по сети, или использовании большого числа вложенных модулей и классов...Подробнее: https://www.opennet.dev/opennews/art.shtml?num=55187
Ещё тупее критерий придумать не смогли?
ну ты если такой умный то предложи
На каком основании вы требуете от собеседника что-то предлагать? Он высказался в том, что исследование нУжно? Или Вы считаете, что констатация факта неадкватного критерия оценки означает обязательное наличие более адекватного критерия?
> констатация факта неадкватного критерия оценки означает обязательное наличие более адекватного критерия?для местного диванного эксперта -- да
Потому что: критикуешь - предлагай, предлагаешь - делай, делаешь - отвечай. А иначе ты, дядя, 3,14-ун просто.
отвечая - критикуй. goto start.
99% коментариев на Opennet это все вокруг дураки, а я то умный такой (как в прямой, так и непрямой форме). Аргументы не принимаются, все-равно все дураки, а я то прямо орел.
Да это не комментарии виноваты -- это мы с вами, братцы, порой зачем-то друг перед дружкою выпендриваемся (и то не тем, чем хоть стоило бы; а некоторые так вовсе перед собой любимым с одного адреса переписываются).Так что кому опеннет не тот -- предлагаю вооружиться зеркалом. Да и сам пойду-ка рожу в нём изучу на предмет углов и радиусов, что ли.
В коей то веке здравая мысль от Шигорина ))
Сложно кода это сложнее, чем считать кол-во включений файлов.В целом надо смотреть на каждый проект, смотреть на его структуру. Модульный проект чаще будет более усложнённым, но его будет легче разрабатывать и сопровождать. Надо смотреть на саму кодовую базу, она большая? Проект сложнее.
но тут субьективно достаточно получаеться, а по поводу кодовой базы - она может быть поделена на модули так, что работая над одним, не нужно даже названия других знать не надо (драйвера в ядре)
Большое количество подключаемых файлов косвенно может говорить о том, что в данном файле кто-то пытался скрестить ежа и ужа. То есть нарушен паттерн - одним куском кода решать одну задачу (в идеале).
Но любой нормальный програмер и так всегда стремится уменьшить количество подключаемых файлов.Было бы здорово увидеть в отчёте места в проекте, где найден совпадающий либо похожий код, это гораздо важнее. Если свести "велосипедостроение" к минимуму, то это сильно понизит количество и сложность кода, и повысит управляемость проектом.
> Большое количество подключаемых файлов косвенно может говорить о том, что в данном файле кто-то пытался скрестить ежа и ужа. То есть нарушен паттерн - одним куском кода решать одну задачу (в идеале).мне видится как раз наоборот - соблюдён паттерн. Выносишь в отдельный файл кусок кода, который решает одну задачу (класс, функция), которые могут быть использованы в более высокоуровневых задачах (классах, функциях) и т.п.
Он же не тупой, зачем ему предлагать ещё тупее критерии? Странный вопрос.
Следует согласиться, критерий слегка некорректный. Ссылки на файлы... Можно было бы проанализировать количество строк в функциях, модульность — как-то более в человеческом ключе.
Вообще есть инструменты автоматического котроля "сложности". Хорошее правило - если код сложным - сборка в CI ломается.
Есть много метрик:
https://checkstyle.org/config_metrics.html#ClassFanOutComple... (что описано в этом посте)
https://checkstyle.org/config_metrics.html#CyclomaticComplexity - кличество ветвистых "if'ов"Другие виды сложностей https://checkstyle.org/config_metrics.html
В общем сложность нужно держать под контролем автоматизированными инструментами.
Предлагаю индусский вариант... самый бесполезный и очевидно равный предложенному выше =)
С тем же успехом можно считать количество объектов, количество присвоений и количество ветвлений.По факту если рассмотреть код в котором включений будет меньше и код в которых их будет больше, в первом случае можно будет сломать голову от кода, лямда функций и за каждым деревом будет ещё дерево и за ним будет ещё а за ним будет ещё и так далее пока человек не потеряет нить. А вот модульный код, даже с большим количеством включений будет понять легче.
Чем он тупой-то?
Оверинженеринг и овердекомпозиция - бич современных "прожектёров".
Тем, что не показывает ничего. Кто-то включил не один а 2 файла, какой ужас.
Зачем так примитивно лгать? Не "не один, а два", а "больше пяти".
Речь не про include заголовочных файлов, как я понял, а про связи между модулями. Хотя тут тоже тот ещё вопрос: в тех же проектах на C может быть всего 2-3 заголовочных файла на пачку модулей...
Вместо того, чтобы написать строку со сложением двух величин, вызвали хелпер, который обратился к сервису, тот через провайдер создал колбек обработчик, который передал менеджеру очередей, из которой задание извлек обработчик и вызвал таки этот колбек, что и привело к сложению двух исходных величин.
Зато избавились от дублирования кода, и складывать теперь умеем хоть через mssql, хоть на гпу.
Проблемы начнутся, когда это счастье окажется в inner loop, а величин будет море.
В итоге оно потребует фермы из 20 64-ядерных обработчиков и полдня для того, что нормально написанное приложение сделает на i386 за минуту.
https://singaporedatacompany.com/blog/more-developers-more-p...
усложнение кода есть одна из современных тенденций, к сожалению
Усложнение неизбежно для относительно крупного проекта. А серебряной пули до сих пор нет.
Решение очевидно, особенно для опенсорса - жёстко очертить задачи и область применимости продукта и не пытаться сделать всё. В пределе - то самое "делать что-то одно и делать это хорошо" из юникс-вэя.
Ты только что изобрел философию Unix из 80х.
Он только что сам на неё и сослался (а не претендовал на изобретение). Ну, _включил_ по упоминанию. :-)
Какой ты умный. А мы то и не догадались без твоего комментария. Как у тебя дела-то, много продал дистрибутивов за 100 рублей?
Т.е. вместо файлового менеджера — куча программ. Как-то не нужно.
Файловый менеджер сегодня это обёртка над другими утилитами. Ну это если нормальный файловый менеджер.
вот и выходит, что философия "делать что-то одно и делать это хорошо", применима только к утилитам, а не к "обёрткам".
> вот и выходит, что философия "делать что-то одно и делать это хорошо",
> применима только к утилитам, а не к "обёрткам".Ну почему же. Хорошо оборачивать чужой код тоже нужно уметь.
Усложнение есть одна из тенденций эволюции, всего живого
И неживого. Рекомендую почитать работы некоторых Нобелевских лауреатов.
Барака Обаму и Нельсона Манделу?
если что то усложняется - "это эволюция свойство всего" и становится всё понятно что так и должно быть :)
а если код рефакторят и упрощают - это свойствор мёртввого?
Обычно мёртвого, усердно косящего под живое. А действительно живое -- оно простое и красивое, и остаётся таковым.
> А действительно живое -- оно простое и красивое, и остаётся таковым.Но ты может и простой, но совсем не красивый.
Я бы не согласился, в ДНК может быть много мусора, который не используется, но является пространством для возможной дальнейшей эфолюции или защитой от неудачных реверсивных мутаций или обмена фрагментами между парными хромосомами.В организме целом может быть множество рудиментов и неудачных "решений", появившихся эволюционным путём.
Например, человеческий глаз имеет слепое пятно, т.к. "вывернут наизнанку": у него светочувствительные клетки находятся снаружи, а нервы внутри. У моллюсков наоборот и зрение у них острее.
У жирафа возвратный гортанный нерв проходит от мозга через всю шею до сердца, огибает какую-то артерию и возвращается обратно в гортань.
Просто эволюция не умеет выбираться за пределы локального максимума.
Усложнение кода сигнализирует о его неоптимальности.
Никто не запрещает не пользоваться ООП в PHP.
в списке сам PHP, а не проект, написанный на нём с использованием ООП
Чел открой глаза, там Laravel...
твоя правда, но чувак выше не про него явно писал
Для одной странички приемлемо.
Если константы вместо того чтобы хардкодить их прямо в коде вынести в отдельный подключаемый файл constants, то код становится проще и понятнее, а не сложнее.
Это один подключаемый файл. У вас осталось еще 4.
4-5
Если у тебя столько констант, что их надо выносить в отдельный файл и использовать из разных мест - это и есть показатель сложности кода.
1 сложность - файл локализация
2 сложность - файл конфигов
3 сложность - подключение stdlibУ вас остался один файл на подключение или ваш проект обосрут на опеннете.
P.S. ruby, python, etc... смеются в сторонке храня все в глобальных переменных
> P.S. ruby, python, etc... смеются в сторонке храня все в глобальных переменныхТы упоролся или да?
Сложность 0 - стандартные "общеобязательные" инклюды
Сложность 1 - 0 + стандартные "редкие" инклюды
Сложность 2 - 1 + 1 инклюд с иерархией рабочих объектов
Сложность 3 - 2 + 1 инклюд с самописным внешним коннектором
Сложность 4 - 3 + 1 инклюд фалов служебных объектов или констант или функций работы с UI
Сложность 5 - 4 + 1 инклюд библиотеки ресурсов или локали
---- < здесь какой-то хрен-с-горы сказал, что твой код слишком сложен для пятиклассника (по мозгам) с гитхаба
...
---- < Здесь находится код с гитхаба уровня /б
...
---- < Тихий Кит и Синий Дом
...
---- < Сверхсущества
...
---- < Б-г
Представим себе физико-математическую вычислительную прогу. Скорость света, элементарный заряд, h, могут потребоваться в разных модулях программы. Не вбивать же их значения каждый раз в нужных местах?
Зачем, есть 'rand = srand(nullptr); double h = rand.next();' ?
По одному критерию оценивать подобные вещи - это даже хуже чем глупо.
Выкатите-ка своё исследование по иным критериям - мы оценим. Вот это будет конструктивно.
А какой, простите, кафедрой вы заведуете, чтобы оценивать? Если дадите мне повышение степени, я могу написать.
А ты всё ещё не догадался? Кафедрой оценок уровня потенциального усложнения кода открытых проектов.
Почему в ответ на публикацию в бложеке я должен запилить целое исследование?Ты мне, может, хоть много денег даш сперва? Вот это будет конструктивно.
Хороший критерий.
Загляните в любой код хипстерских проектов на модных язычках.
Да и в код хипстерских проектов на менее модных язычках.
Какая-нибудь простейшая библиотечка может содержать 50 файлов с разными классами из пяти строчек, часть из которых НЕЯВНО (автозагрузка, фиг ли) ссылается на половину оставшихся.
По опыту - зачастую проще выкинуть и/или переписать самому максимально просто, с меньшим числом багов и большим числом функций. Причём это времени занимает меньше, чем пытаться поддерживать это оно, которое тянется из разных источников, постоянно меняется и начинает кривить-косить.
Загляни в старый проект на сишке --- а там инклюды.
PHP - достаточно старый проект на сишке?
Ну так вот, он далеко не в начале списка.
(и про недостаточную его сложность тоже ничего рассказать не получится, шах и мат)
Заглянул. Эти пять строчек (для virtual/abstract блюпринтов) или 1500 строчек (если уже работа с sealed/final классом идет) легко читаются, позволют сконцентрироваться на самом классе или конкретной задаче. Константы не размазаны по всему коду, а поименованы и всунуты там, где им и место. Никаких магических чисел. Читать удобно, раскуривать еще удобнее.Где твой бох теперь?
Ты не понял.
По пять строчек кода, НЕ описания класса. Куча коротких бессмысленных методов, в т.ч. однострочников.
Вызовы ради вызова.
Никаких virtual/abstract я не упоминал.
(больше лефтпадов, хороших и разных, если упростить)
> переписать самому максимально просто,в результате
> Какая-нибудь простейшая библиотечка может содержать 50 файлов с разными классами из пяти строчек,
часть из которых НЕЯВНО (автозагрузка, фиг ли) ссылается на половину оставшихся.
Ох уж эти переписыватели.
В результате переписывания подобной хреноты вместо (реально) 10-20-30 файлов получается 1-2-3, со стройной структурой и очевидным кодом.
Согласен, критерий странный. Не сказал бы что адекватный.Если развернуть все инклюды в какой-нибудь Кваке, то их будет по 10-20шт на один .c, не?
Или даже в простом хеллоуворлд-подобном проекте будет с десяток стандартных хедеров на всякие printf.
Ну вот потом сравниваем сколько инклудов в кваке и холловорде - и получаем неплохое приближение к соотношению их сложности.
зато квака вполне себе комфортна жила на 8 мегабайтах оперативки часть из которых еще жрала системаа
Странный критерий или нет, но похоже на правду.
Господа, нас обманули, расходимся. Посыл статейки ясен: пишите все программы одним файлом и не будет усложнения кода. На модульность программ и разделение ответственности Мартин клал. Исследование не стоит затраченного на него электричества.
> Исследование не стоит затраченного на него электричества.как и поддержка комментариев здесь
Неужели так сложно понять? Для того, чтобы усложняющийся проект жил и поддерживался, его сложностью надо управлять. Как один из инструментов - разбиение на файлы. В итоге количество файлов становится метрикой сложности.Грубо говоря, если ты ещё можешь тянуть проект без модульности - значит он совсем простой. Усложнился - пришлось разделить, выделить какую-то общую функциональность для реюза. Ещё усложнился - берём фреймворки и так далее. Ну или там берём фреймворк изначально для хелловорлда и получаем кучу притащенной сложности - что прекрасно отразится метрикой.
Бьем проект на 100500 микросервисов и ваша логика относительно количества файлов и сложности разбивается об стенку намазаную йодом.
Не так: если вы разделили код на модули, вы снизили его сложность, а не повысили. Если вы этого не сделали, возможно вы просто в состоянии это сделать из-за сложности существующего кода.Большое число файлов может означать, что за кодом следят и следуют определенному походу. Например, в джаве нормально на каждый класс создавать по файлу, просто так устроен язык. Даже если это класс из 10 строк. В пхп скорее всего так никто не будет делать. Можно упомянуть и обратную механику: в пределах пакета (файлы в папке) в джаве не обязательно что-то импортировать, а в питоне каждый файл независим и импорт придется добавить даже при такой же структуре файлов
Если вам пришлось это делать - то значит у вас уже сложный проект
>Visual Studio Code - 60.3%.Это высер Майкрософт? Тогда не нужно.
Тут не учтены зависимости зависимостей. Зависимости самого Electron чего стоят.
Ну им ничто не мешало, откровенно говоря, ещё пройтись и посмотреть цикломатическую сложность функций и методов как минимум.
А зачем?
Ведь любая проблема имеет очевидное, простое и да, неправильное решение.
джаваскрипт - дерьмо
Не поспоришь.
Зачем его придумали и почему до сих пор не заменили?
Гугл все устраивает?
Очень странный критерий.
Изначально похоже сделано было допущение, что модульность это только про борьбу со сложностью и ничего другого. На этом всё и построено.
Но ведь модули могут создаваться для разделения поддержки разных архитектур, выделения подсистем с отдельным сопровождением, для удобства отключения не всегда нужного функционала и т.п. Также не заметил корреляцию с объёмом этих модулей.Получается если большой модульный "переусложненный" проект слить в один единый файл, что он вдруг станет совсем не усложненным (никаких импортов совсем). Хотя по факту он сильно усложнится.
Возможно в рамках одного языка/платформы/подхода/функционала еще можно как-то сравнивать относительную сложность двух приложений, но например каждый язык исходя из своей выразительности и синтаксических возможностей накладывает свой отпечаток. Получается язык с плохой модульностью способствует написанию без усложнений. Типа на мотоцикле ездить безопаснее чем в машине, т.к. там нет ремней безопасности.
Не. Просто очень жёлтый критерий. Выделенный для громкого заголовка и месяца вялых бурлений.
Замечательный критерий, надёжный как швейцарские часы. Вот хочу я, например, написать программу, пусть для работы с JSON.- Импорт реализации строк (зачем свои велосипедить)
- Импорт реализации массивов
- Импорт реализации хешмапов
- Импорт библиотеки для парсинга JSON (если повезёт - она реэкспортит все нужные компоненты, перечисленные выше)И это я ещё не начал саму программу писать.
Ты забыл про i/o (+1) и создание асинхронного потока для парса (+1).
И это даже без привязки к системным либам, тянущимся со всеми ими.
А потом юзеры ещё и ГУЙ захотят…
И веб админку
Поглядел по ссылке, да я не Ъ, только для линуксового ядра. Интересно что это там за 16,8% магических сишных файлов без единого #include? Заголовочные файлы с константами?
Там походу ещё и не учли, что некоторые заголовочные файлы всегда инклюдятся самим kbuild'ом, без явного #include.
Критерий - помёт.
причем тут ты?
Будешь выделываться - утоплю.
Т.е. простыня на 10000 строк проще чем 100 файлов по 100 строк? Ну ок.
Зато Хруст на 3-м месте!
Не удивительно: в Rust поощряется модульность и используется на всю катушку.
еще реализация этих модулей не была похожа на ребенка в инвалидной каляске.
С одной стороны, критерий действительно отражает сложность *отдельно взятого* проекта. Но в реальности разбиение на модули - хорошая практика именно *борьбы* со сложностью, просто учитывать проекты нужно в совокупности, а не по отдельности.Например, если есть два проекта A и B, которые оба зависят от модулей C и D, то получится, что каждый по отдельности проект имеет сложность 3 (A, C, D и B, C, D), но все вместе они имеют сложность 4, а не 6.
Самый простейший и работающий критерий - это количество коммитов ОТ НОВИЧКОВ. Если нуб открыл проект и смог разобраться - это годный проект! :)
И как быстро нубы сведут всё в ноль.
На это есть управляющий проектом - оценивать и принимать код. Главное - что нуб может разобраться в структуре кода. Неважно, сколько там классов, подключенных либ и т.п.
Брэд.
В целом я поддержу Gigi с одной оговоркой:
- сложный проект может все ещё доступен для понимания новичка, если хорошо написан и хорошо документирован комментариями.В этом смысле я бы всем рекомендовал поковыряться в PostgreSQL. Сложность там зашкаливает, но благодаря вылизанности и обилию комментариев, человек с мозгами (даже если он нуб) может всё-таки более-менее разобраться.
Не всегда, правда, достаточно хорошо, чтобы быть способным написать неглючный патч. Но хотя бы какой-нибудь написать.
В целом, вопрос о том, как померять сложность довольно любопытен. Более того это не просто бесцельное любопытство, он обладает и практической полезностью: если бы у нас был бы критерий, то на этапе проектирования программы мы могли бы оценивать разные проекты и сравнивать их по сложности. Или после, оценивая разные подходы к решению, мы могли бы выбирать самый простой.Сия статья, как бы там не писали анонимы выше, не претендует на изобретение финального критерия. Она просто берёт какой-то критерий, и показывает нам результаты применения этого критерия. Статья -- это в большей мере исследование критерия сложности, а не сложности опенсорц проектов. Все критицизмы выше -- это результат того, что в переводе акценты оказались смещены.
Скажем есть принцип DRY (Don't Repeat Youself[1]), но некоторые говорят, что DRY для сосунков, и правильнее следовать принципу WET (Write Everything Twice) -- Кармак как-то агитировал в эту пользу, говоря о том, что писать обобщённую реализацию на двух примерах использования, это кошмар и приводит в конечном итоге к невозможности дальнейшей поддержки, вот когда есть две реализации функции, и нужна третья, вот на трёх примерах уже можно.
Критерий, который статья описывает, по-сути, заявляет что WET проще, чем DRY. Но ситуация ведь сложнее DRY в некоторых случаях упрощает жизнь, с DRY реализацией динамического массива, например, я могу быть уверен что вне вызовов метода этого массива всегда выполняются инварианты "arr->len <= arr->size", "arr->buf != NULL" и "для любого i (0 <= i < arr->len) arr->buf[i] -- не UB". Это очень упрощает жизнь. (Хотя и усложняет тоже: если на стеке любого потока есть стековый фрейм любого из методов динамического массива, то все гарантии коту под хвост, любой из вариантов может быть нарушен в это время).
Короче, сложность -- это сложно, но такие статьи радуют: люди пытаются померять сложность, может когда-нибудь кто-нибудь и придумает, как её померять хорошо. Впрочем, мне кажется, что эта статья слишком простую модель психики программиста использует, уровня правила 7+-2[1]... Мне кажется, занятно было бы попытаться определить "сложность" как функцию символа кода, которая говорит о том, сколько инвариантов программисту надо держать в голове, чтобы написать следующий символ, не совершив ошибку. Ну, типа если я написал "(7+", то дальше должен быть аргумент совместимый с операцией +, первым аргументом которой является целое число, и ещё потом надо не забыть закрыть скобочку. Возможно при этом результатом сложения должно быть число, на которые накладываются ограничения типа 0<=x<=len, иначе будет ошибка выхода за границы массива. Затем сверху ещё требования к алгоритмической корректности кода, и бла-бла-бла... И если бы такую функцию определить, а затем ещё научится считать программно, то после этого можно было бы попробовать проинтегрировать эту функцию по всему коду, и получить оценку сложности программы, которая действительно будет отражать насколько сложно работать с таким кодом. Или может не будет отражать, но пока не посчитаешь для конкретных программ, не поймёшь.
[1] https://ru.wikipedia.org/wiki/Don%E2%80%99t_r...
[2] https://ru.wikipedia.org/wiki/%D0%9C%D0%...
-- я могу быть уверен что вне вызовов метода этого массива всегда выполняются инварианты "arr->len <= arr->size", "arr->buf != NULL" и "для любого i (0 <= i < arr->len) arr->buf[i] -- не UB"Это пока весь код твой, и нет васян-библиотек xD
В случае васян-библиотеки или просто соседнего индуса (не путать с национальностью) я бы не был так уверен и налепил assert'ов (exception'ов) и прочих аналогов в критичных местах.
Потому что завтра эта уверенность вылетит в трубу^Wуязвимость.
> В случае васян-библиотеки или просто соседнего индуса (не путать с национальностью) я
> бы не был так уверен и налепил assert'ов (exception'ов) и прочих
> аналогов в критичных местах.assert'ы должны быть внутри васян-библиотеки в виде тестов. Так что лучше лепить их не в свой код, а непосредственно в код васян-библиотеки тестами, и отправлять их ему патчами. Глядишь он меньшим васяном станет, а то и вообще имя сменит.
Не все инварианты ты сможешь проверить assert'ами: как ты проверишь валидность указателя? Как ты проверишь размер выделенного куска памяти по адресу лежащему в указателе? И как часто проверять? Каждый раз, когда ты решил поработать с динамическим массивом? Или после каждого вызова каждого метода? Инварианты придумали как раз для того, чтобы разделить ответственность -- ответственность за поддержание инвариантов динамического массива лежит на разработчике динамического массива, если он с этой ответственностью не справляется, ищи другого разработчика.
> Потому что завтра эта уверенность вылетит в трубу^Wуязвимость.
Если тесты включены в код библиотеки, то, чтобы уверенность восстановить, можно прогнать юнит-тесты после обновления библиотеки.
Ещё бы LLVM/Clang исследовали.
ELASTIC - та еще помойка говнокода, тромозящая и неповоротливая как и все их продукты.
Показательно, что бывает, когда смузихлебам ставят ТЗ.