Pull to refresh

Comments 49

Откуда стойкое обращение на Ты :-? Это вроде не men's health & K
Это лишь способ повествования) Каждый, кто читает что-либо, никогда не обращается к себе на вы)
Достойная выжимка, ничего нового, но конспект отличный. Можно распечатывать и класть на рабочий стол
Спасибо) Собственно, с этой целью и создавался данный материал) Чтобы под рукой всегда была краткая памятка того, как стоит писать код)
Спасибо вам за такой труд.
Часто не хватает таких конспектов по книгам. Самому составлять очень лень(
Отличный труд! Но, мне кажется, лучше стараться делать функции чистыми и отказываться от модификации передаваемых аргументов. Если хочется изменить входной аргумент — пусть функция вернет модифицированную копию. Это не всегда возможно, но к этому стоит стремиться. Такой код проще читать и проще тестировать.
… а еще он отлично жрет процессорное время и память (реклама производителей железок)
UFO just landed and posted this here
Используй TODO и FIXME.

Крайне сомнительная рекомендация. Либо делай сразу, либо заводи задачу там, где она не потеряется. А вот уже ссылку на задачу можно добавить в TODO.
Я вот тоже не очень понимаю, зачем приниципиально оставлять TODO в коде, а не создавать задачу в трекере задач. Недавно только чистили код от TODO, которые лежали просто годами.
А TODO и должно ссылаться на задачу. Например сегодня мы работаем с x86, но в будущем нам, возможно, потребуется поддержать ARM. Заводится задача по поддержке ARM'а и всё TODO ссылаются на неё.

Можно ли сразу поддержать ARM? Можно, но не нужно: полноценная поддержка усложнит разработку в 1.5-2 раза, а если вы оставите «мёртвый код» без тестов и/или пользователей, то обнаружите, что к моменту, когда он понадобится — код «протухнет». TODO «протухают» тоже, конечно, но худшее, что с ними может произойти — они станут непонятными и вы их выкините, а странный код, появившийся ради задачи, от которой, в итоге, отказались будет вам мешать долгие годы — так как без комментариев все будут его видеть, но никто не будет понимать — зачем он там.
Без этого вашего пояснения фраза
Используй TODO и FIXME.

вредна. Сегодня с утра один наш разработчик скинул в общий чат скриншот этой статьи с этой фразой. Тогда как у нас в компании всего месяц назад с моей подачи запретили оставлять в коде TODO без указания номера задачи.
Я расставляю TODO и fixme в коде, но логика в том, что ни один TODO и FIXME не попадает в релизный код, без указания на задачу. Т.е. пока я работаю над кодом, в нем может быть неограниченное количество TODO по разным причинам. Например, просто как напоминалка, что здесь пока что затычка и костыль, чтобы упростить разработку другой подсистемы (да, сильносвязанный код зло, но это не моя вина и рефакторинг не всегда возможен). Однако как только завершаются все таски и код отдается на тестирования, для всех оставшихся TODO нужно создать задачи и заменить на ссылки.
Ну, можно создать связку, которая переводит TODO сразу в трекер, для этого вроде уже существуют инструменты
Это призыв к использованию TODO и FIXME в тех случаях, когда нужно пометить, что код нуждается в доработке.
Я часто использую TODO и FIXME, чтобы потом вернуться к месту на которое сейчас не является приоритетным. Проект настроен так, что не собирается если в коде где-то есть эти метки, что помогает не забыть о том, что хотел сделать и не сделал.
В MS VS комбинация кнопок ctrl + w,t открывает окно со списком всех TODO в проекте. В других IDE наверное тоже есть что то подобное.
Чтоб научиться писать хороший код — нужно много писать и читать код, периодически возвращаясь к доработке уже написанного. Без такой практики этот список не поможет, а вот качестве дополнения будет очень полезен.
>>Обработка ошибок — это одна операция. Если в функции есть ключевое слово try, то после >>блоков catch/finally ничего другого в функции быть не должно.
Предполагает вынос блока try в отдельную функцию. Имеет ли смысл выносить в отдельную функцию если внутри блока одна строчка

Автор утверждает, что имеет, насколько помню. Я с этим согласен. Есть метод, который работу работает. Есть тот, который ошибки ловит. И второй не разобран на части первым. И вообще это разные задачи, зачем их перемешивать?


Привыкнуть только никак не могу. Среда разработки и язык не располагают к хоть сколько нибудь быстрому и / или удобному рефакторингу. В Джаву хочу, на Идею… И выделять методы, выделять методы...

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

По мне так наоборот. Не стоит плодить классы с методами без аргументов, в случае нужды будет сложнее понять какие конкретно данные метод берет, на какие другие методы эти данные повлияют, и сложно будет метод переиспользовать.
Нужно стремиться к чистым функциям. Вот вход, вот выход, все сразу понятно из заголовка. Если забирает сразу много данных — сделай интерфейс.
+1
Идеальное — это 1. Что-то вошло — что-то вышло. Прямолинейный поток выполнения, композиция, лёгкость переиспользования. Когда у функции нет аргументов, это значит, что она берёт входную информацию из окружения, а значит имеет побочный эффект. Такую архитектуру нельзя называть «чистой».

this для методов — это не окружение, а один из аргументов.

Да, конечно.


int doSomething() {
  this.data = 42;
  return this.data;
}

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

А почему методы не могут быть чистыми?

Могут, это приветствуется, и вполне заметно улучшает поддерживаемость кода.
Но представим, что все методы чистые. Это значит, что их работа не зависит от состояния инстанса класса, и тогда возникает вопрос: "Зачем эти все методы содержатся в этом классе?"


И есть только один разумный ответ: класс просто группирует эти методы (которые уже просто функции), но если язык позволяет организовывать модули просто с внешними функциями (например, Kotlin, Scala, Rust), то вполне естественно организовать их так.


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

Но представим, что все методы чистые. Это значит, что их работа не зависит от состояния инстанса класса, и тогда возникает вопрос: "Зачем эти все методы содержатся в этом классе?"

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

Вместо return null лучше использовать пустой объект — Collection.empty() или null-объект — EmptyObject().

Объясните, почему так? До настоящего момента приходилось встречать только вариант с null, чем он хуже?
Ну про EmptyObject неоднозначно, а вот пустая коллекция точно реже ведёт к ошибкам (притом не факт, что очевидным), чем null.
Как по мне проще для понимания и использования. В какой то статье (или книге) приводился пример как НЕ надо возвращать значение в стиле:
1) Нет друзей — возвращаем null;
2) Есть один друг — возвращаем собственно объект;
3) Друзей больше одного — возвращаем коллекцию объектов.
Мало того что на null например можно попросту забыть проверить, или ожидать только null или коллекцию не учтя случай с одним объектом, так еще и разное поведение лепить в зависимости от типа возвращаемого значения.
Тогда как при пустой коллекции или коллекции с одним элементом нам бы не пришлось в клиентском коде городить отдельную логику.

Все так. Говоря более формальным языком, пустой список – это константа для монады "список".

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

То есть каждое правило применимо, ну, скажем, в 99% случаев, но поскольку у нас тут чуть больше, чем полсотни правил, то в половине мест хотя бы одно из правил стоит нарушить…

Про это недавно отдельная статья была
Я понимаю что ООП, и во всех учебниках написано, но чем автору насолили статические методы? Про состояния понятно, но с методами то в чем проблема?

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

«Идеальное количество входных аргументов для функции = 0»
Очень спорное утверждение.
В книге очень много спорных утверждений. На самом деле стоит просто отдавать себе отчет почему код должен работать именно таким образом каким он написан. Стоит подумать как его можно улучшить. К тому же это всего лишь рекомендации, которые не обязательно соблюдать. Это не правила, а именно рекомендации)
UFO just landed and posted this here
Приблизительный максимум 20 строк и 150 символов в одной строке

150 символов — это явный перебор. Большенство редакторов ставят отсечку почти на половине от этой величины. И даже это многовато.

Идеальное количество входных аргументов для функции = 0

Если это foo/bar/baz для hello world — да, а так нет.

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

Не обязательно. Это зависит от ЯП.

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

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

If, else, while и т.д. должны содержать вызов одной функции. Так будет читабельнее, понятнее и проще.

Вообще не обязательно. Очень сомнительное правило.
Не обязательно. Это зависит от ЯП.

Пример можно?
Я всего на нескольких ЯП пишу. Ни в одном из них нет ограничений на имя метода.

Если это foo/bar/baz для hello world — да, а так нет.

  • start() — идеальный метод;
  • start(speed) — отличный метод;
  • start(speed, direction, path) — похуже. Сходу и не вспомнишь, в какой последовательности параметры передавать;
  • start(speed, direction, path, maxBias, onError) — комментарии, думаю, излишни.
Пример можно?
Я всего на нескольких ЯП пишу. Ни в одном из них нет ограничений на имя метода.

Ruby. Вполне характерно писать вообще без глаголов или глагольных префиксов.
И если чистые глаголы это ещё куда не шло (#call, #perform или что-то в этом роде), то глагол + ключевое слово — это скорее code smell, чем норма.
И это не ограничение, а соглашение.

start() — идеальный метод;
start(speed) — отличный метод;
start(speed, direction, path) — похуже. Сходу и не вспомнишь, в какой последовательности параметры передавать;
start(speed, direction, path, maxBias, onError) — комментарии, думаю, излишни.

Если аргументов больше ~3 (это эмпирически) — это уже code smell.
Разумно применять keyword-аргументы, если возникает путаница.
Например возьмите любую функцию из C math.h. Там нет глаголов, только существительные: sqrt, sin. log, exp, round и
Если следовать правилам чистого кода, то надо было их назвать calc_sqrt, calc_sin, find_exp и т.д. Делает ли это код чище? Ничуть.
Вы говорите о «общепринятых» названиях, которые
  • применяются в т.ч. в математике
  • приживались годами

и поэтому не вызывают дополнительных вопросов.
А вот на заре моей программистской деятельности SQR и SQRT было сложно запомнить.
Полная запись GetSqareRoot (вполне вероятно) вызывала бы меньше вопросов поскольку не является «набором несвязанных букв» (как я тогда воспринимал) а вполне осмысленным словосочетанием.
Да, помню свои первые попытки программировать. Особенно если учесть что английский я знал никак — почти все для меня было магическим сочетанием символов. Тогда это здорово притормозило.
Ruby. Вполне характерно писать вообще без глаголов или глагольных префиксов.

Я не сталкивался с Ruby.
Например, как геттеры от сеттеров отличаются?

И если чистые глаголы это ещё куда не шло (#call, #perform или что-то в этом роде), то глагол + ключевое слово — это скорее code smell, чем норма.

Из текущего:
Есть запрос (Request), который содержит список параметров (Parameter).
У Request есть метод для добавления параметра в список.
Назови я его add никто не поймет что именно добавляется.
Назови я его addParameter — даже не знакомому с архитектурой человеку будет понятно что именно добавляется в Request.

Будет ли имя addParameter «запахом»?

parameters.add выглядит немного лучше нежели addParameter

Я не сталкивался с Ruby.
Например, как геттеры от сеттеров отличаются?

Немного вклинюсь к вам просто разнообразия ради)
Objective-C
getter: `param`;
setter: `setParam:(value)` (синтаксис неточный)
Т.е. функция-геттер не имеет глагола.
Например, как геттеры от сеттеров отличаются?

# это геттер
def first_name
  @first_name
end

# это сеттер
def first_name=(val)
  @first_name = val
end

Вот и всё различие.
На самом деле таким макаром геттеры/сеттеры не пишут, только если надо переопределить их стандартное поведение.
Дефолтную пару можно сгенерировать с помощью одной строчки
attr_accessor :first_name


Будет ли имя addParameter «запахом»?

Скорее да, чем нет.
Из Вашего примера, скорее всего данный функционал будет имплементирован немного по-другому.
request.params[key]=value

params — это просто словарь, к которому можно обратиться напрямую.
"[]=(key,value)" — это тоже метод.

P.S. Проверил — так примерно в рельсах и сделано. Только там params — это экземпляр класса Parameters, который в свою очередь ведёт себя как словарь.
Спасибо за труд! Было бы круто, если например под каждым пунктом была ссылка на книгу на какой странице это можно почитать подробнее. Например меня заинтересовал какой-то пункт и хотелось бы подробностей, чтобы не искать по всей книге. Было бы очень удобно! Понимаю, что это большой труд!)
Sign up to leave a comment.

Articles

Change theme settings