Как стать автором
Обновить

Комментарии 182

НЛО прилетело и опубликовало эту надпись здесь
Напомнить бывалым, что не написанный код содержит заведомо меньше ошибок, чем написанный.
К сожалению, в последнее время встречаю много огромных «простыней» за авторством именно бывалых (5+ лет разработки), уверенных в себе людей
НЛО прилетело и опубликовало эту надпись здесь
Проблема с объёмом появляется тогда, когда логику проследить становится слишком трудно из-за самого объёма. Бороться нужно именно с такой ситуацией.
А преимущества и недостатки «волшебных однострочников» можно обсудить за дружеской кружкой пива :)
Предпочитаю эффективный код, который делает свою работу и ничего более. А его толкование и описание возложено на документацию. В таком случае не потребует никаких 100 грамм и прочей нервотрепки. А если есть пример, то прекрасно.
А поддержкой документации занимаются единороги, которые это делают идеально.
Есть ответственные разработчики, которые стараются представить свой продукт максимально информативно, чтоб им можно было легко пользоваться, ведь для этого и создается. Прекрасный пример p5.
Конечно, в момент написания кода и комментов они полностью синхронизированы и имеют смысл. А потом приходит реальность, начинают проходить дни, месяцы, годы, другие разработчики, баг фиксы, добавление функционала, приход новых и уход старых людей… и только единороги непрерывно обновляют документацию…
Это и есть пример безответственности. Но тем не менее, наличие документации, избавляет от необходимости изучать код, кроме случаев, когда что-то идет не так. В таких моментах поможет быстрее разобраться в коде, нежели делать аналогичное с недокументированным куском.
К сожалению, реальные люди ошибаются, забывают, отвлекаются, недопонимают что-то итд итп. В результате, комментарии могут (и будут) рассинхронизироваться с кодом. Это лишь вопрос времени (или количества модификаций кода). Нельзя ожидать, что все разработчики будут идеальными всегда.
Я не про комментарии строчек кода, а про описание работы функций.
И что, работа функций остаётся неизменной навсегда?
Или же вышеупомянутые единороги неусыпно следят, чтобы описание продолжало соответствовать реализации?
метод в 20 строчек и комментарии к нему на 40 строчек — все равно меньше, чем метод на 100 строчек.

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


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


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


Вообще рекомендую прочитать книгу "Чистый код: создание, анализ" за авторством Роберта С. Мартина, там очень много полезного написано, в том числе и то что в статье перечислено.

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

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


Ещё комментарий может говорить о хаках и трюках, которые (зачем то) понадобились.

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


i  = 0x5f3759df - ( i >> 1 ); // what the fuck? 

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

НЛО прилетело и опубликовало эту надпись здесь
Встретились как-то аббревиатуры для программеров. Тоже можно в комментариях использовать.

image
Обычных болтающихся комментариев в коде стоит избегать, так как обычно единственное что можно понять из комментария, так это то, что у автора не получается писать достаточно выразительный код.
Мои комментарии часто бывают в стиле «сделано так, потому что другой способ, очевидный, является неправильным или неэффективным».

К примеру, если в delphi создаёшь форму через Application.CreateForm(TForm, formReference), то нужно обязательно вызвать Application.Run, даже если приложение запускается не в интерактивном режиме (можно в Run послать сразу Terminate), другого способа корректно освободить ресурсы этих форм нет.

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

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

На самом деле иногда поражает на сколько люди ленятся читать код без комментариев, даже если он сам себя комментирует через имена его компонентов. Даешь человеку прочитать свой код, чтобы обсудить с ним какую-то его часть — он возвращается с упрёком, мол «где комментарии». Я отвечаю: «а зачем, тут же всё достаточно хорошо расписано, и всё есть в документации», на что обычно я получаю ответ в стиле: «код без комментариев не может быть понятным», хотя на деле это просто человеческая лень, ведь очень демотивирует когда ты видишь исходник на 3 тысячи строк кода (отформатированных по стандарту, определенному проектом, написаным с максимальной выразительностью, и с функциями, тела которых не превышают 20 строк, и обладают единственной ответственностью) без единого комментария. Хотя если приглядеться и начать таки читать, всё читается как текст. Сам читал такой код не раз, сам пишу такой же код на работе.
Если в коде торчит костыль, который так и просит, чтобы его удалили, его можно либо закрепить комментарием, либо переписать всё нафиг (а ещё лучше — на другом языке), чтобы костыли не приходилось вставлять. Можно переписать, но это какой-то не реалистичный подход.
3 тысячи строк кода с функциями, тела которых не превышают 20 строк

150 функций на одном уровне вложенности, каждая из которых может потенциально вызываться из остальных? Я бы наверно тоже так сказал.

не, ну если в блокноте читать, то понятное дело. Никто же не запрещает использовать Ctags, встроенные в IDE фичи, такие как поиск символа и так далее (мазохизм конечно никто не отменял).


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


на одном уровне вложенности

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

не, ну если в блокноте читать, то понятное дело

Так количество функций что в блокноте что в IDE одинаковое) Чтобы понять, что тут делается, надо все их проанализировать.


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

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


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

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

Так количество функций что в блокноте что в IDE одинаковое) Чтобы понять, что тут делается, надо все их проанализировать.
Чаще всего достаточно прочесть название функции. Если вдруг понадобятся детали одной из десятка — лезть глубже в конкретный блок, а не пытаться искать ориентиры в простыне.
Я говорю о случае, когда разбивается слишком подробно. Чаще всего, если мы лезем в код, нас интересует реализация. Если в функции вынесены логически независимые части, тогда да, можно ориентироваться по названию.
Куча мелких функций ничем не лучше кучи строк в одной функции. Названиями переменных тоже можно действия документировать. В данном примере 3000 строк лучше разделить на несколько классов, а не пытаться прикрыть сложность функциями.
Слишком подробно разбираться сразу во всём не стоит) Едва ли можно эффективно держать в памяти все тонкости реализации в таких объемах. Практика показывает, что скорее всего отдельные логические части в 3000 строках точно найдутся. И их не только можно выносить, но и нужно, ведь это основа SRP. Классы — это ведь просто форма пространства имен функций и (возможно) какое-то скрытое состояние.
какое-то скрытое состояние
которое просто является скрытыми параметрами для этих функций, так что как раз пространством имен и является с возможностью инкапсулировать параметры для своих функций для удобства. И только.
Ни разу не встречал метода на 100 строк в котором можно легко отследить логику действий (конфиги не в счет).
«Не нужно додумывать слишком много. Так вы создаете проблемы, которых изначально не было.»

Фридрих Ницше
Знавал я бывалых программистов, которые на моё искреннее удивление: «Ребята, у вас тут метод на 2000+ строк, это ок вообще?» — недоумевали: «А что такого? Всё ж понятно».
Это лучше, чем тупо порезать его пополам, потому что по кодстайлу такие длинные методы запрещены.
Ага, причем с восемью вложенными блоками и с рекурсией.
Не хватает эпиграфа к статье )
«Совершенство достигается не тогда, когда нечего добавить, а тогда, когда нечего отнять».

Угу, любимое занятие: "фиксил багу… стёр 200 строк кода, теперь вроде работает правильно".


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

Я ничего не имею против коротких лямбд. Для того они и существуют. Но когда внутри callback-а кто-то ставит в очередь Runnable внутри которого ещё и дёргает map по коллекции, становится очень печально. Эдакий callback hell на стероидах.
на универсальность не претендую :)
Правило — если в лямбда-функции хочется написать императивный код, а не выражение, нужно выносить в отдельную функцию.

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

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

Удобство довольно сомнительно. Локальная функция требует значительно больше места для её описания (+4 строки). Плюс это не отменяет того факта, что функция вместе с её локальными функциями должна умещаться на экране.
Лямбда не эквивалентнта локальной. Последняя компилируется в более производительный код, умеет работать с дженериками. Кроме того, лямбда-функции логично вписываются в рекурсивные функции, когда инициализирующий метод один, а локальная функция — такой же, но с дополнительными параметрами из инициализирующего.
Всё бы ничего статья, но…

Структура — это тоже код. Декларации — это, внезапно, тоже код. И даже когда перед нами обычный ООП без «закидонов» — уменьшение количества функционального кода всегда выливается в увеличение объема структур (это помимо случаев изобретения велосипедов, когда надо просто использовать уже где-то имеющийся код).

Когда слишком много структур — это ничем не лучше, чем когда слишком много кода. Когда видишь перед собой простую редко выполняющуюся задачу категоризации (а-ля «разложить общую кучу элементов по нескольким по определенному признаку»), решаемую с помощью пары интерфейсов, десятка классов, и «умно» примененных паттернов — схватиться за пистолет хочется нисколько не меньше, чем при чтении метода на 1000 строк.
Истина конечно же где-то посередине.
А она тут вообще есть? Сомневаюсь.
Посудите сами, если у вас есть однородная задача на 10 000 действий, то это задача на 10 000 действий. Вы можете её разбить на 1*10000, 10*1000, 100*100, 1000*10 и тд структурных единиц, но от этого она меньше не станет. Она останется задачей на 10000. Ваши разбиения лишь добавляют в неё энтропию. Да, разбиение работает в качестве оглавления, но, в целом, оно ни лучше и не хуже простого комментирования кода.
Вкусовщина. Одним людям проще кушать слона по частям. Другим проще прочесть код, как книгу, — от корки до корки. Третьи будут ныть в любом случае, а четвёртые вообще не будут читать, позвонят разработчику и вынут всю душу вместе с содержимым кишечника.

Я не имею в виду программу с ГУИ, обработкой командной строки, работой с БД и расчётным блоком. Это разные задачи — структурные единицы, которые должны быть разнесены. А бывают иные задачи, разбиение которых ничего не даёт, кроме эстетического удовлетворения и проблем с передачей параметров. Стоит оно того или нет? Я не знаю.
Посудите сами, если у вас есть однородная задача на 10 000 действий, то это задача на 10 000 действий. Вы можете её разбить на 1*10000, 10*1000, 100*100, 1000*10 и тд структурных единиц, но от этого она меньше не станет. Она останется задачей на 10000.

вот только для среднего изменения в одном случае надо будет прочитать 10-15 блоков по 10 действий, а в другом — 3-4 блока по тысяче
И какой из этих двух вариантов лучше? У меня вот нет однозначного ответа. С одной стороны, перемножив всё получаем 150 против 4000 действий, и первое как будто лучше, с другое — не надо недооценивать «10-15 блоков» как самостоятельную большую проблему. Возможно, это большая проблема, чем разница в 30 раз в количестве действий.
существует миллион причин почему разделять код на блоки лучше:
1. читается код намного больше раз, чем пишется. Монолитный код приходится читать полностью, в то время как модульный — только интересующими нас кусками.
2. человеческая память ограничена определенным количеством действий. Один раз прочитав метод и зная, что он вычисляет какой-нибудь f(x,y,z) и не имеет побочных эффектов, повторно можно его не анализировать. Большие методы, однако, держать в голове полностью невозможно.
3. поведение маленьких модулей проще, значит проще составить модель их ожидаемого поведения, протестировать и гарантировать корректность
4. маленькие методы легко переиспользовать, слишком большие — невозможно. Поэтому в плохо разделенном коде чаще встречается дублирование, которое само по себе ведет к нескольким другим проблемам.

А теперь еще раз вспомните, что все эти действия над кодом надо делать каждый раз при попытке внесения изменений.
1) Далеко не всегда это так. Очень далеко не всегда. Есть отдельные модули, которые пишутся раз и навсегда просто потому, что их менять нет смысла. Откройте, например, OpenSSL\Crypto и посмотрите историю изменений. Половина исходников там с бородатых времён практически неизменна: менялись только лицензии и, возможно, фичи для обхода предупреждений компилятора.
Работает — не трогай.
а вы не историю изменений читайте, а сам код, и учитесь на его примере
Нет уж, сами читайте код, sha1 и AES я лучше по аналитическим формулам изучу.
И, уж извините, OpenSSL не является эталоном качества ни по удобству, ни по качеству структурирования, ни по документированности, ни по надёжности, ни по тестам.
Там есть причина — максимальная производительность. Можно записать красивее, но будет медленнее. В библиотеке это очень важно.
Вы как будто комментарий не прочитали и отвечаете. Или я так непонятно написал? По вашим пунктам
1) я и писал про читаемость кода
2) а этот пункт как раз и был предметом сомнений: я совсем даже не уверен, что держать в голове 15 коротких блоков проще чем 4 длинных, и даже более того, сталкивался с ситуациями, когда эти самые короткие блоки, поделённые на отдельные функции и вложенные друг в друга, меня ужасно бесили при чтении кода — гораздо приятнее было бы прочитать одну простыню, чем ворох мелких фрагментов; если у вас такого никогда не было — это не значит что всем так же.
3) опять та же проблема: вам надо сделать кучу мелких проверок или одну большую: усложнение графа связей между функциями само по себе добавляет проблем, и, может быть, оно добавит меньше проблем, чем решит благодаря маленькому размеру модулей, а может и нет
4) ну, да, но переиспользование не везде будет требоваться; если вы пишете какое-то апи общего назначения — то да, вы не можете заранее полностью знать контекст его применения, а если вы пишете конкретный продукт под конкретную задачу — то уже можете знать, что какая-то функция, хоть она и могла бы быть переиспользованной в другом случае, но конкретно в вашем проекте она используется всего 1 раз и больше не будет; у многих есть склонность создавать абстракции и апи общего назначения там, где их «не заказывали» — это далеко не всегда хорошо.
вы выбираете какой из двух примеров плохо структурированного кода лучше не имея представления о том, как должен выглядеть хорошо структурированный код. Недавно выкладывали статью про исследование кода LLVM, в числе прочего указали процент больших (> 70 строк) функций. Их процент ничтожен

Сложность теста пропорциональна сложности метода. Проще метод — проще тест.

Проект редко (никогда не) заканчивается сразу после реализации первично обговоренного функционала. Лучше сделать код расширяемым чем рефакторить на каждую хотелку.

Я сравниваю два варианта, которые были предложены вами же выше. Причём тут код LLVM непонятно. ПРо тесты это отдельная тема но про них в начале речи тоже не шло.


Проект редко (никогда не) заканчивается сразу после реализации первично обговоренного функционала. Лучше сделать код расширяемым чем рефакторить на каждую хотелку.

Во-первых, это просто не так. Во-вторых, добавление функционала не означает, что из этого нового функционала может быть вызвана произвольная функция. В-третьих, такие преждевременные абстракции имеют свою цену, и если вы заранее сделаете 100 ненужных апи функций, а потом, в процессе доработки, 10 их них пригодятся — то весьма сомнительно, что вы в итоге выиграли. Я не говорю, что делать апи заранее ненужно (более того, есть места, где оно понадобится потом с вероятностью >70%), но делать его везде — определённо лишнее, и есть места, которые в вашем проекте его потребуют с вероятностью, например, не больше 5%, но вы, забыв о рабочей задаче, начинаете вместо специализированного инструмента делать софт общего назначения "для всех".

Маленьких методов много. И когда код разбит больше чем надо, при анализе надо все их держать в голове с учетом контекста.
У меня был кейс недавно однозначный. Нужно было сохранить 50 тысяч файлов с именами 1,2,3 и т.д… Можно было всё в одну директорию, можно в 5 по 10000, в 500 по 100. Я выбрал в 50 по 1000. Тогда директория [удаленно] открывается и не зависает, и можно нужный файл быстро в файл менеджере найти. Остальные варианты ощутимо хуже.
Так что всё по своей мере.
Согласен с вами. Если задача требует 10 000 действий, то от них никуда не денешься. И разбиения только увеличивают количество сущностей.
Но правильно выбраное разбиение на абстракции может разбить эту задачу на (условно) 10 * 10 * 10 * 10 структурных единиц (не только методов, но может быть и классов). В зависимости от того, на сколько глубоко нужно изучить механизм решения задачи, можно будет прочесть (условно) один метод на 10 строк. Или ещё 2-3 метода по 10 строк и так далее. Гораздо легче сфокусироваться, погружаясь в детали.

Я столкнулся с таким, казалось бы излишним, разбиением в open source проекте, к которому готовил pull request, и оно меня спасло. Оно того стоит.
А ещё бывает, что рядом с сорцами лежит маткадовский или латексовый файл, где лежат те же формулы, что реализованы в исходниках, а исходники лежат в двух вариантах: без оптимизаций и RAEP_TIEM. Внутри всё было сплошным полотном, но по соседним файлам и меткам всё было очень читаемо, на уровне методички по матану.
Я такое видел лишь единожды, и мне очень понравилось.

Я не собираюсь спорить, какой вариант лучше. Разбиение на структурные единицы — инструмент. И им тоже нужно уметь пользоваться.
Когда видишь перед собой простую редко выполняющуюся задачу категоризации (а-ля «разложить общую кучу элементов по нескольким по определенному признаку»), решаемую с помощью пары интерфейсов, десятка классов, и «умно» примененных паттернов

А если такая задача решалась бы с помощью пары интерфейсов, ДВА десятка классов, НО БЕЗ «умно» примененных паттернов — это было бы лучше 1000 строк?
Статья хорошая, но есть вопросы:
1. Это вольный пересказ нескольких глав из книг Фаулера и Йордона?
2. Статья про код, про ООП и про Java, но ни строчки кода на Java?
И маленькое дополнение: Хотелось бы увидеть как автор доказывает и показывает , что вот этот код ( здесь пример кода) был таким, а потом стал таким и что из этого вышло и к чему привело. Или так писать плохо(тут пример плохого кода), а так писать хорошо (тут пример хорошего...) Как говорится — всё познается в сравнении.
1. Нет, пересказа не было.
2. Была такая мысль. Но проиллюстрировать проблемы с большим объёмом кода можно только большим объёмом кода. Который никто не любит читать :)
есть пара оговорок. 1. зачастую написание более абстрактного кода позволяет упростить дальнейшие поддержку, тестирование и развитие, но это ценой увеличения объема. Это прямое противоречие принципу «ни строчкой больше»
2. код должен быть разделен на логические блоки, а не параграфы. Ветку if “на 20+ строк” имеет смысл выносить в отдельную функцию только если она будет являться самостоятельной логической единицей.
Спасибо, всё правда. Видимо, я плохо описал пример с if. Там речь шла о большом количестве кода внутри «веток». Пока дочитаешь до else, условие успеет уйти с экрана. В таком случае код «веток» следует вынести (функции, объекты и т. д.)
Так вот Antervis, если я правильно его понимаю, пишет полностью противоположное Вам. Что выносить ветку в отдельную функцию следует только если она будет являться самостоятельной логической единицей, а количество строчек — не аргумент (или вторичный аргумент?). Так, Antervis?
важно скорее то, что существует две трактовки комментария на естественном языке в обсуждении написания/чтения кода.
«Гладко было на бумаге...»

Хорошо работает только если нет костылей. Если есть reflection, или дыры в тестах, т.п. — любой рефакторинг выливается в рефакторинг зависимых частей, и такой «проект» растет, как снежный ком. И даже хуже — если не довести его до конца, приходится добавлять еще костылей.
В действительности количество кода косвенно влияет на количество ошибок:

а вот теперь по остальным выводам:

Сэкономите кучу времени себе (на написание) и другим (на чтение).

Есть метод XXZZ12YYu(int a)
Он вызывается во всем проекте несколько и в разных местах.
вызов занимает 1 строчку, а вот что он делает, анализ метода занимает огромное кол-во времени, плюс написание тестов (если их нет) что бы понять конкретный результат.

Уменьшите количество ошибок в системе.
Выше косвенно влияет, но только при условии, что в системе остальное работает безупречно.

Упростите поддержку и развитие системы.
Ситуация стандартная, когда не понимаешь как это работает и посмотреть негде, а есть только 2 строчки кода. Большие затраты времени на анализ «маленького» кода.

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

Код должен быть лаконичным, что не эквивалентно понятию «Короткий»,
что означает — каждый следующий элемент кода должен следовать логически из предыдущего.
Нет кода — нет проблемы, всегда так говорю своим начинающим коллегам. И Вам советую

Присоединяюсь, только у меня фраза звучит так: "Идеальный код — это не написанный".

Сгенерированный тоже сойдет. Но отсутствующий — еще лучше.

Вот как раз перед праздниками я случайно нашел причину лагов веб-интерфейса. Она была в коде который должен был бороться с лагами. Удалил его и лаги исчезли…
Если больную почку удалить, тоже сперва полегчает.
А потом возможно придется покупать аппарат для гемодиализа.
Почка в человеческом теле выполняет какую-то функцию. А код иногда не делает ничего полезного, совсем. К примеру, тот код который я удалил — ускорял на 20мс обработку нажатия на кнопку «сохранить» (что было никому не нужно) ценой замедления на 20мс обработки любых нажатий клавиш на клавиатуре (что всем мешало).
)))
А зачем тогда кто-то этот код туда вставил?
Нет, есть вероятность, что это какой-то атавизм, который забыли вырезать после вырезание его связей. Нет смысла спорить.
Именно так. Сначала этот код управлял доступностью кнопки «сохранить» — но из-за лагов от такой идеи быстро отказались, а код остался…
Не написанный вообще. Варианты:
— уговорить клиента вообще отказаться от фичи (уровень Бог);
— переиспользовать готовые фичи;
— что-то поправить или настроить в конфигах;
— взять готовую библиотеку.
И только если ничего из вышеперечисленного невозможно — писать код. Причем писать как можно меньше (минимально возможное количество кода, позволяющее реализовать фичу).

Это помогает:
— сократить время разработки;
— упростить саппорт.
Вы слишком экзотический пример приводите.
Вот прихожу я к вам и говорю — «мне нужно вот с этих пяти сайтов собирать информацию об их товарах, чтоб как только что новое появляется — у меня сразу вся инфа с ценой.»
Достаю и держу в руках пачку денег

Давайте по своим четырем пунктам попробуйте пройтись. Начните с конфигов)
  1. Нет ли у этих сайтов фидов с ценами? Может можно добавить продукты в избранное и получать цены о них на почту? Может уже есть сервис-агрегатор и вам нужно купить подписку на него вместо разработки своей системы?
  2. Если у меня уже есть какой-то парсер, я могу добавить ваши сайты в него и дописать только необходимую часть.
  3. Если у меня есть парсер (допустим я уже делал такие задачи) — возможно в нем есть вариант конфигурировать правила разбора разметки, пользуясь например XML или YAML.
  4. Если все с нуля — поищу какие есть готовые библиотеки для парсинга, для отправки HTTP запросов, для отправки писем.
    И только потом напишу код-склейку.
1. нету, естественно. вы такое вообще видели?
2. нету, конечно
3. см. 2
4. О каком парсинге речь? html-парсинге? Это подножный стандартный инструмент. Всё остальное всё равно придется ручками писать. А любое готовое типа универсальное решение которое вам (или вы) будут впаривать в итоге выйдет боком и намного дороже пары сотен своих строк.
Я даже не беру в расчет время, необходимое на изучение и настройки этих готовых решений, и их ошибки. И вообще, зависание на чужой код.
1. Есть функции добавления товара в избранное, когда на почту приходят уведомления о появлении товара в наличии или изменения цены. Есть фиды, которые магазины отправляют какой-нибудь яндекс-маркет, может быть есть возможность его получить.
2. нет так нет
3. см. 2
4. Я подумал, что вы хотите со страницу интернет-магазина цену брать, поэтому html-парсер. Возможно, есть другие способы. Что плохого в зависимости от чужого кода, если он решает задачу? Опять же, я не имею в виду первую попавшуюся поделку с гитхаба, есть решения с большим сообществом и долгой историей. Я предпочитаю, чтобы баги фиксил кто-то другой.
Я просто сам писал несколько раз такое. На php вытащить со страницы нужную информацию в нужном формате — 10-20 строчек кода с какой-нибудь simple_php библиотекой (это де факто стандарт для парсинга html в php). Не преувеличиваю. Еще немного кода засунуть это себе в БД или еще куда. Ради этого зависать на чужой непонятный софт? Вы в инете времени в 5 раз больше потратите на его поиск чем сам кодинг.

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

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

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


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


  • дальше будет как обычно — нехватка времени на поддержку, исправление похожих багов в разных похожих участках кода и никто не готов выделить время на рефакторинг.
  • а не надо писать лишнее. Выделяются только те абстракциии, которые нужны. Если когда этот функционал будет использован в третий раз — абстракции можно будет доработать.
  • качество кода это не предмет согласования, а прямая обязанность программиста. А если проект планируется дольше чем на полгода — еще и головная боль.
нехватка времени на исправление похожих багов в разных похожих участках кода и никто не готов выделить время на рефакторинг.
Рефакторинг проводится тогда, когда ты возвращаешься к этому коду — при исправлении багов или реализации новой функциональности. Поэтому специально выделять на него время нужно лишь в крайне редких, сложных и запущенных случаях, когда были допущены существенные ошибки в архитектуре приложения (а чаще это даже вредно, так как есть риск попасть в ловушку «рефакторинг ради рефакторинга», сжирающую любой выделенный на неё объём времени без каких-либо реальных выгод).
а не надо писать лишнее. Выделяются только те абстракции, которые нужны
Сложновато сделать вывод о том, нужна ли абстракция (и в такой ли форме?), если она встречается только дважды, причём второе применение — новое, для которого всегда может последовать команда «Отставить!».
Если когда этот функционал будет использован в третий раз — абстракции можно будет доработать.
В результате чего придётся вносить изменения (и рисковать багами) в первых двух применениях. Зацепленность не просто так считается одной из важнейших проблем при программировании.
С выделением в функции кода только ради именования я бы тоже поспорил, но даже единожды скопированные без изменения несколько строк кода — абсолютное зло.
даже единожды скопированные без изменения несколько строк кода — абсолютное зло.
Часто встречаются ложно-одинаковые куски кода, которые ни в коем случае нельзя выделять в абстракции, потому что хоть они и «скопированы без изменения» — но изменения в них точно будут, просто не на данном этапе.
Например, инициализация элементов UI: несколько диалогов в руках у разработчика могут быть идентичными — но стоит им попасть в руки дизайнеров, и каждый получит индивидуальный цвет, вкус и запах.

Кастомизация цвета/вкуса и запаха, имхо должна быть не в коде

Дизайнеры работают после программистов? (и почему дизайнеры вообще противопоставляются разработчикам?) Что мешает отложить копипастинг до момента появления реальных различий?
Это не так. Потому что одинаковыми они могут быть только в этот конкретный момент времени.
Необходимость копирования можно проверить представлением в динамике — «если у нас логика изменится здесь, надо будет менять там?», «может ли быть, что там должно работать не так, как здесь?».
Чаще всего различия удаётся задать параметрами. Даже если нет, то лучше копировать по мере необходимость и сразу редактировать, чем плодить такие вот «заготовки».
Если человек не страдает самоконтролем, то никакие добрые советы ему не помогут. Неоднократно во время PR review наблюдал откровенный говнокод, которого могло бы не быть, если бы человек просто посмотрел на свою писанину второй раз.
Мне стоило некоторого труда научиться задавать себе вопрос, а не говнокод ли я написал только что?
К сожалению, многие разработчики не задают себе такой вопрос вообще никогда.
Вся беда в том, что в реальном мире помимо кода существуют еще дедлайны и плохая постановка задач.
И сферический идеальный код в вакууме почти никому в реальном мире не нужен (а тем очень немногим, кому нужен — как правило, не за большие деньги, если вообще хоть за какие-то). В реальном мире вообще код не нужен, а нужны инструменты для решения проблем клиента (которые он толком описать вам не сможет, во всяком случае не с первого раза), и желательно чтоб еще вчера, и чтоб максимально недорого.
Невменяемые сроки и плохая постановка задач — все это есть. Но в хорошем проекте это скорее исключение, чем правило.
Я, конечно, люблю идеальный код, но не являюсь его неуёмным фанатом. Должны существовать измеримые критерии качества кода, и никакой код в проекте не должен быть хуже, чем предусмотрено этими критериями. Критерии, конечно, у каждого проекта могут быть свои.
Очень хорошо, если заказчик понимает, что качество кода непосредственно влияет на качество продукта, на стоимость его развития и поддержки. Если не понимает — лучше инвестировать время в разъяснение, окупится.
А так — да. Никому не нужна корова, всем нужно молоко, шкура, мясо. Никому не нужен бетон, всем нужны мосты и здания. Никому не нужен Х, всем нужен У.
Должны существовать измеримые критерии качества кода

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

В обоих случаях первичны, опять же, деньги. А не «сколько нам нужно грамотных проектировщиков, чтоб всё было красиво», и тем более не «сколько в среднем строк на метод» и прочее, имеющее непосредственное отношение к коду. А дальше кто как разумеет, тот так и идёт от денег к конкретным инструкциям для тех же джунов. Кто-то эмпирическим путем определяет, как «строки на метод» относятся к стоимости поддержки, кто-то пользуется своим (и чужим) прошлым неудачным и удачным опытом, чтоб понять, что некий набор методик и рекомендаций скорее всего позволит вписаться в сроки и бюджеты, и так далее. Путей очень много.
Самоконтроль нужен всем, это правда. Очень помогает, если на проекте есть инструмент code review (GitHub pull request, Gitter, Upsource etc.) в котором несложно предложить коллегам посмотреть на новый код.
Про Java добавлю, что в последних версиях (начиная с 7/8) разработчики языка довольно много переносят из сторонних библиотек в основную. Сейчас ту же Guava довольно редко когда приходится использовать.

С основным посылом полностью согласен: довольно много некачественного кода пишется как новичками, так и «бывалыми» (всегда так работал и было норм). А вот про рецепты… Все-таки главное читабельность, а не количество кода (видел прилично компактых нечитаемых примеров в жизни). Хотя метрика «кол-во кода» проще автоматизируется. Просто, этого недостаточно.

Да и не будут это читать «бывалые». А если прочитают, то не согласятся. Иначе бы уже давно исправились. Нужны организационные изменения. Какие — зависит от конкретной организации. Где-то достаточно обязательных code review. Где-то можно внедрить роботов, которые блокируют PR, если там слишком плохой с формальной точки зрения код. Где-то еще что-то.
Код заслуживает быть вынесенным в отдельную функцию не только тогда, когда его планируется переиспользовать, но и в целях улучшения читаемости.

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


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

Области видимости — это не проблема, а благословение, позволяющее экономить сложность.


Если вы выносите в функцию вроде бы обособленный кусок кода, а он тащит с собой 5-10 параметров, значит что-то тут не так. Например, математические расчеты перемешаны с логгированием, получением/записью данных и пр. Другой случай — у вас есть блок данных, которые везде приходится таскать вместе (скажем, длина, ширина и кисть рабочей области рисования), тогда имеет смысл выделить класс-контекст.
Именно выделение функции позволяет такие проблемы обнаружить, и почти всегда после рефакторинга понимаешь, что новый код стал более понятным и чистым.


Еще лучше с длинными простынями. Часто при распутывании таких "нетривиальных" случаев оказывается, что покрыты не все результаты ветвления и в некоторых случаях получатся странные результаты либо явные расчетные или инфраструктурные (забыли считать/модифицировать общие данные) ошибки.

Интересно, как бы можно было разбить на маленькие куски кода, например, такой код:
image
Сhart of how Slack decides to send a notification

1) Это не код, а блок-схема. Вероятно, она была нарисована, когда авторы совсем запутались в написанном коде;)
2) В этой блок-схеме есть два очевидно отдельных куска с разделением в "What's the user's channel notification pref for this device". При этом нижнюю часть скорее всего можно упростить, т.к. есть пересечение у channel и global notifications (например Mentions). Также если делать не единственные точки выхода (YES/NO), то из схемы пропадёт куча объединяющих стрелочек и она станет не такой страшной.
3) Главное, эта схема описывает реальную сложную бизнес-логику. Ее тоже не стоит переусложнять (пользователю будет непонятно), но это другой случай. Описывающий эту логику код поместится на 1-2 страницах, и с учетом хорошей документации в этом нет проблем. Но есть еще код, который вытаскивает из внутренних структур значения переменных, которые тут в if'е. Если он подмешан к коду бизнес-логики, то именно тогда и получается простыня, требующая рефакторинга.

Отлично объяснено, спасибо!
сколько времени сожрёт её вызов чисто на запуливание-выпуливание параметров в/из стека.

Ого! Вот с таким уровнем оптимизации я никогда не сталкивался. Простите уж Java-программисту его наивность :)

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

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


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

Ревью — вообще проблема и один из самых больших bottleneck'ов в процессе доставки продукта конечному пользователю. И на больших, и на маленьких кусках кода. Человек, который делает ревью, не может адекватно оценить решение, потому что он не в контексте задачи. Обычно на ревью находят всякую стилистическую шелуху, которую при наличии тестов можно поправить в любой момент.


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


Переиспользуйте код, выделяйте абстракции, не стесняйтесь.

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


Чтобы писать меньше кода, нужно:


  • перестать реализовывать бесполезные фичи
  • решать с помощью кода только текущие проблемы, а не мечтать "когда мы будем как Facebook, такое простое решение работать не будет"
  • сначала написать падающий тест
  • потом заставить тест проходить
  • закончить рефакторингом
  • если рефакторинг не идет — оставьте код в покое, позже все равно поймете как сделать лучше
1. Проблема не в размере кода а в его сложности и читаемости. Можно написать короткий код в стиле «смотри как я могу» в который сам автор через месяц минут 10 будет втыкать перед тем как поймет что он делает а можно написать в 2 раза длиннее но так, что любой дурак сразу поймет.

2. Искать библиотечки тоже не всегда нужно. Иногда проще свелосипедить чем тащить зависимость ради одной тривиальной задачи. Тоже самое с переиспользованием. Часто лучше скопипастить, если это что-то что 100% не будет меняться, чем зависеть от других классов, проектов.

За 10+ опыта вывел для себя следующие приоритеты:
1. Простота, читабельность, понятность кода;
2. По-меньше всяких абстракций и ООП, только тогда когда они реально нужны;
3. Слабая связность и изорилорваность, даже если придется копипастить (без фанатазима), так, чтобы в случае чего код можно было безопасно выкинуть или переписать не затрагивая другого функционала системы;
4. Линейный, императивный код, в идеале такой чтобы определенную логику можно было проанализировать прочитав один файл сверху вниз один раз а не прыгать по разным файлам в разных проектах;
5. Код дружелюбен к тестам и дебагингу.
Лет 25 назад читал подобные тексты, чуть ли ни слово в слово. Неужели ничего не изменилось?

Кодинг — это как лингвистический язык (русский, английски). Должна быть культура его разговора, его обучения. Правила, стилистика, синтаксис, орфография и всё остальное, а не феня гопника.
Раньше кодинг был искусством. Помню, еще на первом курсе давали задачки: написать код на любом языке, который в качестве вывода выдаст сам себя. Сейчас так могут?

А сосед написал тетрис на ассемблере, самый быстрый, который я когда либо видел — фигурки падали с ускорением свободного падения на 486. Да еще и с алгоритмом, когда он сам собирался.

А другой накодил сетевой 3д-шутер на VAX-VMS на псевдографике.

В той атмосфере код любой программы старались довести до совершенства. Это было как личная калиграфическая роспись.
Раньше кодинг был искусством. Помню, еще на первом курсе давали задачки: написать код на любом языке, который в качестве вывода выдаст сам себя. Сейчас так могут?

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

Раньше кодинг был искусством.

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

Тогда у вас будут поляроидные фотографии, но не будет рукописных портретов.
НЛО прилетело и опубликовало эту надпись здесь
Так-то да, но если копнуть глубже, то без доктора физических наук не будет работы у слесаря.
И дело в том, что поляроид — это не сам ремесленник, а его инструмент. Нам дали полароид на время. РКН недавно заблокировал что-то, и полрунета перестало работать. Потому что полароид — ихний. Почему у нас аналогов этих гугловских сервисов нет? Свифта нет? Потому что все радостно бегают с полароидами и думают, что крутые мастера.
Полароиды делают те самые художники, ремесленник его не сделает. И Гугл и Майкрософт сразу же выдергивают из России любого начинающего художника, как увидят, на 100К плюс полный соцпакет и переезд для всей семьи.

Так что до поры до времени — да, полароид удобней.
НЛО прилетело и опубликовало эту надпись здесь
Вы не правы. Когда-то давно мой друг уезжал в Микрософт. Я помню его уровень, помню, как он летал на интервью, знал о заданиях, которые ему давали, в каком отделе он работал, что делал, уровень организации труда. уровень его коллег. Потом он перешел в Гугл перед его взлетом. Так вот и там и там именно на 99.999% искусство. И даже простой гугловский сервис делают художники, хоть он и кажется элементарным.
Рено логан штампуют ремесленники, но создавали его не ремесленники.
НЛО прилетело и опубликовало эту надпись здесь
Что-то я не понял, каким образом из моих слов следует, что художники пишут не чистый код.

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

«Внутренний» — это, в том числе, следование парадигме ООП (если берем java) и лучшим стандартам кодинга.
НЛО прилетело и опубликовало эту надпись здесь
да, просто разная трактовка терминов
Это я не к вам апеллирую, а так, вслух грущу, что России художники не нужны…
на первом курсе давали задачки: написать код на любом языке, который в качестве вывода выдаст сам себя. Сейчас так могут?

Довольно-таки бесполезная вещь, имхо.


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

И сейчас стараются. Но только если данные объёмом в десятки ГБ ВНЕЗАПНО не влезают в лимит памяти 2ГБ, или бездарно написанные алгоритмы имеют сложность О(N^6) при N порядка 3000. Суровая коммерческая разработка — это вам не тетрис на PHP.


Не люблю ностальгию по системам с 640КБ. Особенно когда сравнивают "вот тогда" и "а сейчас". Сравнивать не совсем корректно: объёмы расчётов на порядки больше; компиляторы генерируют сопоставимый по скорости с ассемблером код, этого кода иногда получается аж гигабайты — столько вручную не написать; и т.д.

Вообще-то, я имелось ввиду качество обучении. Вы в школе и вузе много «довольно-таки полезных вещей» нарешали?
Думаю, и ещё через 25 лет мало что изменится. Иногда нужно напоминать и о таких простых вещах )
Не являюсь особо опытным, но считаю что 95% java-прогеров болеют ООП головного мозга. И данная статья культивирует болезнь. Например либа от сервиса антикапчи разбита на штук 20 классов. Ну что смеяться? Два-три самое то. Или биржевой бот (без аналитики, только коннектор) — вообще под сотню. И эти люди пишут, что метод на 100 строчек слишком длинный? :)
а почему именно java?
ООП оно и в африке ООП, к языку не привязано вроде
У разных языков и их фанатов разные интерпретации понимания термина ООП. Реализации реально очень разные. И как правило программисты в рамках одного языка пересекаются чаще, чем в рамках разных. И это формирует общий стиль мышления и кодирования.
Ну, во-первых, java — первый распространенный язык высокого уровня, построенный на парадигме ООП. ООП в ее крови, поэтому выражение «95% java-прогеров болеют ООП головного мозга» бессмысленно.
Во-вторых, не программеры, а языки программирования больше или меньше «тяготеют» к ООП, поэтому реализовать одну и ту же ООП структуру можно и на php, и на java, но для опытных программеров на java это естественно, а на php возможно проще процедурно решить задачу.
Тем не менее реализация ООП в php (классы, объекты, наследование) вполне себе полная. В java просто более строгая, академическая.

В общес, про ООП головного мозга не понятно. То же самое, что сказать, что у java программеров — main головного мозга. Ну да, есть немного, но это фича, а не баг.
:-). Да причем тут php и процедурно.

Систему можно разбивать более чем одним способом. А еще разный способ подходит под разные задачи.

Но. Когда систему бьют, чтобы бить; когда абстракции выделяют бездумно и в огромном количестве; когда количество смысла на строку текста приближается к нулю. Вот тогда мы получаем ООП головного мозга.
А, под «ООП головного мозга» вы имели плохой ООП анализ и дизайн? И он чаще встречается у java-программеров?
Это не знаю…
Примерно это, да. За разными языками закреплены разные стереотипы, не обязательно обоснованные. Я просто объясняю соль шутки.

У людей, долго пиливших на яве в кровавом энтерпрайзе, вырабатывается характерный стиль: очень много слоёв абстракции. Думаю, причина этого — не сам язык, а особенности процесса разработки (вероятно, обоснованные в той отрасли), они потом на любом языке так пишут.

Не знаю как сейчас, а раньше java был обычным языком, не обязательно enterprise. На нем писали любые библиотеки. Веб-приложения. Много клиент-серверных. Даже десктопные приложения под виндоуз (ну, под все ОС, ессно) Очень много опен-сорса было. Глоток свободы после годов тирании С/С++ )))

И везде там было ООП. Не помню особо проблем с разбором чужого кода…
НЛО прилетело и опубликовало эту надпись здесь
Ну почему, и в java можно почти всё загнать в main(argv[])
ООП — это образ мышления. Структурирование данных, вычленение сущностей и поиск зависимостей. Одно и то же техзадание можно перевести в архитектуру будущего ПО очень по-разному — удачно и неудачно.
Поэтому архитекторы и дизайнеры получают в несколько раз больше простых программеров.
Де факто никто не мешает обходиться статическими методами и полями, используя классы как пространства имен. Тем более, что статический импорт там разрешен. Такое себе ООП)
95% не-java-проггеров (js, это я про вас) впадают в другую крайность и не структурируют код вообще. На мой взгляд лучше читать чрезмерный ООП, чем ту кашу, которую производят js девелоперы.
Вот да, дайте мне лучше пожалуйста «больных ООП на всю голову», чем то, что довольно часто нынче творится на ниве фронтэнда в js.

Как например (извините, наболело) этот их «серьезный, популярный, эффективный» ангуляр, разработчики которого в один прекрасный момент просто заявляют: извините, но сделать наследование наших деклараций и инъекций слишком сложно, поэтому мы этого делать не будем. Нет, нас не волнует, что мы типа косим (туториалами, модульностью, и тэ дэ) под ООП, но не имеем реализации базовых принципов ООП. Вас волнует? Ну, ваши проблемы.
Oблечь техническoе зaдaние в кoд не прoстo. Некoтoрые прoгрaммисты делaют этo с трудoм. aрхитектoры программного обеспечения, высококлассные рaзрaбoтчики, нaoбoрoт, пoстигли этo искусствo. И все же сoвершеннaя фoрмa кoдa еще недoступнa. Ею влaдеют oчень немнoгие. Тaйнa зaключaется в пoлнoй гaрмoнии фoрмы и сoдержaния. Любoй элемент языкa, oперaнд, идентификaтoр в свoем вырaжении имеет глубoкoе знaчение, пo свoей семaнтическoй идее. И вoт этa-тo идея и ее реaлизaция в кoде дoлжны нaхoдиться в пoлнoм сoзвучии. Некoтoрые прoгрaммы oсoбеннo сильны именнo этим сooтветствием. Кaждaя прoгрaммa имеет свoй ритм, если прoгрaммист, ее нaписaвший, этим ритмoм влaдеет. В твoрениях великих рaзрaбoтчикoв пoрoй мoжнo улoвить этoт ритм, нo мнoгие пишут целые прoгрaммные кoмплексы, никaкoгo ритмa не сoблюдaя и дaже не пoдoзревaя o нем. Тaкoй кoд в рaзрoзненнoм и беспoрядoчнoм ритме или сoвсем без негo или сoвсем не читaется, или зaбывaется скoрo. Нo те, пусть этo будет хoтя бы мaленькaя прoгрaммкa, где ритм сoблюден и пoстигнутa музыкa кoдингa, те читaются легкo, и прoгрaммисты их реюзaют. Нaписaннoе нa любoм языке прoгрaммирoвaния мoжет быть дaнo в любoм ритме и любoй тoнaльнoсти, нo при услoвии сooтветствия сoдержaния с фoрмoй. Следует пoмнить при этoм, чтo кaждый элемент языкa имеет свoй звукoвoй ключ и сoчетaется в кoде с рядoм других элементoв пo свoему внутреннему сoдержaнию, звукoвoму ключу и связи сo свoей семaнтикoй, кoтoрыми oблекaется весь кoд, кaк музыкaльнaя идея oблекaется звукaми. Именнo музыкaльнoй симфoнии мoжнo упoдoбить хoрoшую прoгрaмму. У великих рaзрaбoтчикoв этa гaрмoния мыслей и выражений языка программирования инoгдa вырaжaется oсoбеннo яркo. Зoвут тaких людей мaстерaми кодинга. Незримoе вoздействие прaвильнo и гaрмoничнo пoстрoеннoгo кoдa oсoбеннo великo. Внутреннее егo сoдержaние стaнoвится oсoбеннo выпуклым, кoгдa с ним внешняя фoрмa сoзвучнa. Тaйнa прoгрaммирoвaния oчень слoжнa и немнoгим дoступнa.
А есть такой редактор кода, в котором параллельно коду автоматически рисуется блок-схема алгоритма?
Или наоборот, создание блок-схемы приводит к автоматическому написанию кода?
А есть такой редактор кода, в котором параллельно коду автоматически рисуется блок-схема алгоритма?

Параллельно — не знаю. Но по определенной команде построить точно можно (Visual Studio).


Или наоборот, создание блок-схемы приводит к автоматическому написанию кода?

Есть. Но сгенерированный код не отличается хорошим качеством.

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

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

Ну и проработанный UI редактора тоже крайне важен…
RAD Studio. Автогенерация кода из алгоритма. Ну и «детские» Java, JavaScript редакторы так вполне умеют. Еще видел для C embed, неплохой вариант, если вы железячник, а не программист.
Не пишите лишнего

ООП с документацией и тестами

heh, classic
НЛО прилетело и опубликовало эту надпись здесь
Обычно начальство тупое, и поэтому именно такое. Но должен быть проджект манагер, который видит нюансы. А кроме того, в развитом айти рынке петя бытро найдет в два раза более высокооплачиваемую работу среди таких же аккуратно пишущих не для себя, а для проекта разработчиков.
По своему опыту. Не обязательно фанатично избегать длинного кода, но крайне желательно избегать копи-пасты. Если хоть какая-то часть кода скопировалась, с минимальными изменениями, либо (особенно) вообще без — это повод создать новый метод или процедуру. Так как я пишу на Делфи, который позволяет вложенные процедуры, то, бывает, выделяю из совсем уж длинных методов логические части в отдельные вложенные процедуры, удобно.
главное, чтобы определение вложенной процедуры не встречалось посередине длинного метода (незнаю, допускает ли Delphi такое) :) а так отличный вариант решения, да.
Допускает анонимные процедуры (лямбда-замыкания) прямо внутри кода. Но обычно мало кто их использует, поэтому особо не говнокодят :)

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


Проверьте, не решал ли кто-то до вас в этом проекте такую же (или сильно похожую) задачу.

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


Знайте и любите утилиты и API собственного проекта. Особенно, если ему больше полугода. Там могут найтись жемчужины, которые сэкономят вам десятки строк кода.

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


Ещё знайте и любите популярные библиотеки для вашего языка или платформы

Иногда только из-за одной функции подтягивают кучу зависимостей.


Код заслуживает быть вынесенным в отдельную функцию

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

Ни в коем случае не претендую на «серебряную пулю», которой не существует. Просто отметил определённые перекосы и трудности, с которыми сталкиваюсь в повседневной работе.

Все ваши замечания очень даже по существу, и их стоит применять, организуя свой код и проект. Хотя публика может и не оценить предложение использовать копипейст :)
Отличной иллюстрацией проблем с использованием библиотек в индустрии стала истоия «левого отступа» в JavaScript, так что о ней нескоро забудут.

А вот с «обёмной, но линейной функцией» я бы поспорил. Сколь линейной бы она не была, если она не лезет в экран, её пора разделить на «шаги».
А вот с «обёмной, но линейной функцией» я бы поспорил. Сколь линейной бы она не была, если она не лезет в экран, её пора разделить на «шаги».

Вам какую книгу удобно читать — если текст последовательный (пусть и не влазит на одну страницу) или разбит по отдельным кускам-абзацам, которые хаотично и бессистемно раскиданы по всему тому?

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

Допускаю, что «бессистемная раскиданность» не доставляет мне проблем благодаря используемому инструменту (IDE). Читать код с большой степенью косвенности в Vim/Emacs наверное так же сложно, как читать распечатанную википедию (без браузера).
Когда я работаю с кодом, я предпочту читать краткое содержание, влезая в детали только там, где это действительно нужно.

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

Для начинающих достаточно одного простого совета —
пишите лаконичный минимальный идеальный в вакууме и сразу правильный на все случаи код.
все.
так они его и так пишут. Разве нет?
Работал с программистом, который очень любил «не писать лишнего». В его коде как раз были методы-простыни на тысячи строк. Спорил с ним на ревью по поводу выделения в отдельный метод, его рассуждения были примерно такие:
— Этот метод будет вызываться один раз, значит в коде будут плюс две-четыре лишние строки на сигнатуру функции, скобки, разделяющую пустую строку и т.п., зачем мне лишние строки?
Ну и, несмотря на то, что я считаю это ужасным подходом с точки зрения качества кода, стоит признать, что формально-то он прав, кода действительно становится больше. Поэтому я удивился, когда увидел в статье
Код заслуживает быть вынесенным в отдельную функцию не только тогда, когда его планируется переиспользовать, но и в целях улучшения читаемости.

Так что я не понял посыл. С чем предлагается бороться: с количеством или низким качеством? Или под словом «код» здесь понимается только содержание методов?
Второе. Основная боль — огромные, непомерно раздутые методы/функции (в комбинации с вложенными структурами),
Ну, это, конечно, да. Согласен с тем, что это боль. Но вот лично у меня эта боль не основная. С огромным методом хотя бы понятно что делать — анализировать и разбивать. Т.е. есть конкретный файл, в нём конкретный ком грязи, конкретно его чистишь в несколько заходов — и понимание приходит, что оно делает, и мелкие баги сразу под пристальным взглядом всплывают и фиксятся. Если время есть, то это даже какого-то рода медитативное дело. Даже настроение улучшается: вроде как какой-то дурак намусорил, а ты всё прибрал и почистил, молодец. (Даже если намусоривший дурак — это я полгода назад, лол)
Моя основная боль начинается от ООПшного комка грязи, разбросанного по разным файлам, между которыми нужно скакать, пытаясь угадать зависимости. Когда непонятно даже, куда в принципе стоит смотреть. А усиливается боль от пучка зависимостей между огромными модулями (пускай даже не слишком плохими внутри), с которыми уже вообще фиг знает, что можно сделать, и любая правка подобна магии. А ещё больнее, когда все остальные модули — не твоя зона ответственности, и ничего менять в них по регламенту тебе не положено. Ещё хлеще, если часть этих модулей вообще проприетарное ПО с закрытым кодом, и ничего там нельзя изменить в принципе.
Сорян, что не в свою ветку влезаю. Но хотел бы поделиться самой большой своей болью. Попался мне проект на андроиде, где вообще каждая мелочь прокидывалась через EventBus. Порядка 100 ивентов, с выбросом и отловом в огромной куче мест. Там пока по цепочке пройдешь от причины к следствию проблемы уже забываешь, как тебя зовут вообще.
Вообще-то))) в ООП это вторичный вопрос — большой код для метода, или небольшой, читаемый или нет.
Есть объект, его свойства, есть необходимые методы — паблик, протектед — интерфейс к нему, Остальное разбивается на прайвет.
Во главе — объект, его свойства и методы. А что написано в методе волновать должно только тех, кто этот метод будет дополнять/переписывать.
Если ваш программер выдает рабочие готовые библиотеки, нечитаемость его кода терпима. Если это команда — обязательны правила для всех. В противном случае — желательны.(премируйте грамотно пишущих)
НЛО прилетело и опубликовало эту надпись здесь
Вы перечисляете так называемый форс-мажор. Он, грубо говоря, отдельно в договорах оговаривается, под него свои риски, своя страховка, естественно.
Это всё до первого бага или первого изменения требований. Тогда-то и придётся залезть в реализацию объекта и схватиться за голову.
Если программист (1)выдаёт идеально работающий продукт, который (2)не нужно будет дорабатывать, тогда конечно не так важно, как оно написано. Первое происходит обычно никогда, а второе — обычно когда продукт никому не нужен.
Возможно я один такой (ибо ни у кого больше не встречал), но вообще стараюсь писать код исходя из того, что место на экране бесплатное и нечего его жалеть. На мой взгляд даже соседние блоки строк в методе нужно разделить лишней пустой строкой, если мы от одного этапа какой-то работы к другому например переходим, а в не в общую кучу наваливать.
Если же так все экономить фанатично, то даже, казалось бы, линейная и длинная простыня в методе, которую сверху вниз прочитать можно, становится расплывчитым набором символов и ситуация еще больше усугубляется.
НЛО прилетело и опубликовало эту надпись здесь
>… Они [программисты] знают, что большую часть времени они этот код читают…

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

Они подразумевают идеальное качество всего предыдущего кода проекта, законченности внутренних библиотек, справедливости их документации и близкого к 100% покрытия тестами. Иначе, вместо того, чтобы написать лишние 200-500 строчек, мы можем залезть не в «жемчужину», а в ведро червей, где выяснится столько проблем, о которых умалчивали (и забыли), что время на их исправление вырастет в десятки раз.

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

Бизнесу это не нужно. Сданные задачи считаются сданными. Как бы мы не верили в чудодейственную силу agile, но убедить тех, кто был счастливым свидетелем выполненной работы, в том, что ее необходимо существенно доделать — плохая идея.

Вам это не нужно. Ведро червей — это ведро червей. В своем велосипеде на 200-500 строчек вы бы могли применить несколько изящных идей, которые вам правда нравятся, а вот в чужом коде вы в любом случае будете считать wtf/minute.

Продукту это не нужно. Он не проживет столько времени, чтобы разница в поддерживаемости лишних 200 строчек стала по нему бить. Зато старый его функционал будет гарантированно делать ровно то же, что и раньше, даже если вы не знали, что именно (а пользователи вот знали, и любили).

Большая часть проблем энтерпрайза — это как раз подобные проблемы и холивары на эту тему. Я правда, по той причине его и покинул, ибо принцип write it once, run it everywhere throw it away мне понравился больше. То есть, вот микросервисы — это хорошо. Боремся за чистый API, разумную переиспользуемость, компонетность, и наличие внешних тестов в не меньшем объеме, чем внутреннем. А то как оно там внутри устроено — ну, если без крайностей, то кому до этого дело есть? Либо такой микросервис проживет десятки лет, но его еще десять раз перепишут с нуля, либо через пару итераций просто выбросят. Есть исключительные задачи и области, где такой подход показывает себя плохо, но, в целом я предпочел их просто избегать (и на мой взгляд нет в этих областях однозначно хороших решений, уже лет за 40 выяснили).

Возьмем суровую бизнес-логику расчета зарплаты. Желающие могут прочитать статью налогового кодекса про НДФЛ. В 1С Зарплате 2.5 были гигантские запросы на 10 килобайт текста, в которых вычислялось что нужно. В текущей 1С Зарплате 3.0 от гигантских запросов ушли и текст запроса строится горкой процедур из разных подзапросов, но тут есть проблемы что построение запроса это глубина стека в 26 вызовов и 60 подзапросов, причем многие из подзапросов это один и тот же подзапрос с разным именем (например, определение списка сотрудников, к которому потом присоединяются данные из других таблиц). С точки зрения исправления ошибок путь 2.5 проще, ты вдумчиво изучил запрос и наступило счастье. В 3.0 тебе приходится в отладчике идти по всему стеку вызовов, чтобы найти ту самую процедуру, в которой появляются некорректные данные. А когда по кругу вызывается одна и та же процедура, то мозг теряется. )

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

Не знаю как в SAP R3, а в 1с есть визуальный конструктор запросов, который умеет превращать простыню текста в объекты и генерировать текст запроса взад.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации

Истории