Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
зато сильно понижаем… «сложность изменений»
В-третьих, какого чёрта, Вы давите на то, что «более-менее большой проект будет содержать ошибки»? Что это за бабский аргумент?
А Вы считаете, что нельзя писать код без ошибок?
Вы написали «более-менее большой проект будет содержать ошибки». И что? Это и ежу понятно. Но это не значит, что нельзя построить градацию качества кода по количеству ошибок.
Про ваш бабский аргумент я написал верно, попал в самую точку.
Вы вместо достойного аргумента, говорите отстранённый неоспоримый факт, типа: «Почини принтер — Ты ж программист». Стандартный приём «блондинок с большими ногтями».
Мол, качественный код сможет сохранить работоспособность, как можно дольше при изменениях, если в нём изначально меньше ошибок.
Понятия «хорошего» и «плохого» кода субъективны. Рассуждать о них — это пустая трата времени.Понятия «простоты кода» и «DRY» — полностью объективны. Простота/сложность — это количество языковых и смысловых конструкций, а также сущностей, которыми оперирует программа. Оно может быть избыточным (что плохо), или достаточным (что хорошо). С DRY все еще проще — если код дублируется (причем я не говорю только про посимвольное совпадение, естественно, речь про совпадение функциональности) — это всегда плохо. Потому что увеличивается количество сущностей, нужно вносить правки в нескольких местах, резко повышается вероятность ошибки (в одном месте поправили, в другом — нет).
Простота и DRY противоречат друг другу иногда. Что делать в этом случае?Я про это писал в статье — достижение DRY простыми и очевидными методами помогает в большинстве случаев. Если же выходит так, что без объектов, динамически генерируемых через цепочку фабрик согласно XML-конфигурации, дублирования не избежать, надо задуматься — а все ли вообще хорошо с архитектурой? Т.е. на каком-то этапе этот процесс перестает быть линейным и требует подняться на уровень выше.
«Концептуальность» вообще слабо формализуемое понятие, глядя на код как понять насколько он «концептуален»?Если концепция общепринятая, она понятна и так. А если их (концепций) в коде нет вообще, то это определяется по другому — смотрим на код, понимаем, что в нем есть лишние сущности. Т.е. какие-то вещи можно переделать на более общем уровне. Утрированный пример — автолоад классов вместо include в каждом месте, где они нужны. Вот это и есть — применить концепцию.
«Удобочитаемость» это не то же самое, что «удобопонимаемость».Не любой фрагмент кода можно сделать очевидным для каждого, кто его будет смотреть. Бывает объективная сложность описываемого алгоритма или бизнес-процесса, которую не снизить за счет правильного подбора языковых конструкций. Вот повысить можно запросто :)
Особенно доставил последний пункт. Если есть неочевидный код, то почему бы его не написать чтобы он стал очевидным, вместо написания комментариев?
Если же выходит так, что без объектов, динамически генерируемых через цепочку фабрик согласно XML-конфигурации, дублирования не избежать, надо задуматься — а все ли вообще хорошо с архитектурой?
Если концепция общепринятая, она понятна и так
Не любой фрагмент кода можно сделать очевидным для каждого, кто его будет смотреть
Есть много «похожего» кода, но в каждом свои детали. Код простой и линейный. Можно дублирование устранить, сделав функцию\объект с кучей параметров, которые покрывают все случаи. Это убирает повторения, но делает код сложнее. Какой вариант лучше?Код не становится заметно сложнее при правильном подходе. Например, если у нас после попытки убрать дублирование появляется длинная функция со switch внутри, который содержит в своих ветках практически исходные куски кода — это неправильный подход. Функция должна по возможности оперировать параметрами напрямую, а не на уровне условного goto. Т.е. cube(n) делает внутри себя return n * n * n, грубо говоря, а не if(n == 2) return 8, if(n==3) return 27
Есть список «общепринятых» концепций?Есть — на уровне ЯП, отрасли, команды в которой работаешь и мира IT в целом — в качестве примеров я уже приводил автолоад классов и UNIX-конвейеры.
Если же сам алгоритм сложен, то лучше всего правильно назвать метод и в remarks вставить ссылку на описание алгоритма.Ну так ссылка это и есть комментарий.
Есть много «похожего» кода, но в каждом свои детали. Код простой и линейный. Можно дублирование устранить, сделав функцию\объект с кучей параметров, которые покрывают все случаи. Это убирает повторения, но делает код сложнее. Какой вариант лучше?
CFSocketCreateConnectedToSocketSignature — вполне читаемо по мне, и такое везде в CoreFoundation. А уж про Objective-C я промолчу.Не оборачивайте в функцию код из 3-х строк, который нигде более в приложении не используется повторно (и не будет использоваться в ближайшем будущем, а не через 150 лет).
$sum = 0;
foreach ($array as $item) {
$sum += $item;
}
решайте проблему дублирования кода сразу после ее обнаружения (но не раньше!)
array.each(sum), не говоря о циклеЕсть несколько очень похожих блоков кода из 5-10 строк, отличающихся лишь парой условий и переменных, но вы пока не уверены, как лучше завернуть их в функцию? Используйте циклы.
Не знаете, в какой класс/объект положить код нового метода? Просто создайте функцию и положите ее в подключаемую библиотеку до тех времен
Используйте наиболее лаконичные из доступных стандартных конструкций языка. Например, тернарный оператор вместо if-else для блока кода, помещающегося в одну строчку. Не используйте операторы нестандартным, неизвестным основной массе разработчиков образом
известную всем с детства таблицу умноженияСоответственно, если мы оформляем фрагмент в функцию, мы автоматически создаем вопрос для читающего код — а где эта функция еще используется? Если мне надо ее поменять, не сломается ли программа где-нибудь еще? Конечно, есть IDE, тесты и т.п., но эту проблему можно просто не создавать, чтобы потом не приходилось ее решать.
Насчет двух функций — то же самое, нам надо устранять дублирование, а не просто переносить его в другое место. Было 2 похожих куска кода, стало 2 похожих функции — смысл?
Насчет тернарного оператора — я не первый раз уже слышу про то, что какой-то там средний программист не может это прочитать и воспринять, и каждый раз тихо фигею.
$value = isset($value) ? $value : 'default';
, конечно, любой должен прочитать не спотыкаясь, но вот уже что-то типа $value = isset($value) ? is_valid($value) ? $value++ : $value-- : 'default';
Насчёт методов из трёх строк. Всегда (почти) предпочту метод из трёх строк методу из 20. Чаще всего, когда ты читаешь чей-то код, ты пытаешься понять смысл того, что делает этот код, а не детализированную имплементацию, поэтому, если программист писал множество мелких функций, то функции верхнего уровня читаются действительно как «хорошо написанная проза», а если нужны детали — всегда можно заглянуть в детали.У меня вот наоборот как-то получается — понять смысл написанного обычно просто, а дальше нужно в коде что-то поменять, потому что мы его не ради развлечения же читаем, а с какой-то целью. И вот на этом этапе — слишком много маленьких методов и функций создают проблемы, т.к. надо в каждую заглянуть и потом еще половину из них поменять. Что тянет за собой кучу зависимостей из тех мест, где эти функции еще используется. Либо надо все выкидывать и переписывать метод заново.
А вот авторы Growing Object Oriented Software Guided by Tests рекомендует сразу же создавать классы, при малейшем намёке на отдельную сущность, даже если там будет на первых порах один метод.
Практика хорошего кода