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

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

Прочитал «Чистый код»

Неть. Не прочитал, а спросил у LLM

Зато чтобы нам не пришлось

@outlingoоно ответило что "чистый" не значит "безопасный" заставив ещё читать мануал хотя бы «Безопасное и надежное программное обеспечение на примере языка Ада 2012, SPARK 2014» Джона Барнса

То есть на Go/Rust чистый код невозможен, там же нет исключений?

Ключевой момент чистого кода - это от общего к частному (от высокого уровня абстракции к более низкому).

Тут пожалуй соглашусь. Глава "Обработка ошибок" для Go не очень подходит

В Rust есть делегирование ошибок (оператор ? и трейт From<T> к нему), что позволяет держать happy path таким же чистым, как с исключениями.

Спасибо, что сэкономили время на прочтение [считающейся] обязательной книги)

Скопировал текст в перплексити с просьбой переписать на python с примерами кода.

Рекомендую код вставлять не сканами экрана, а через формат кода, с указанием языка.

Выравнивание: Избегайте выравнивания переменных по типу или значению. Оно создаёт ложный акцент и сложно поддерживается.

А мне приятно читать такой код.

Мне тоже приятно в случае если это несколько строчек с переменными +- одинакового размера. Но вот если это начинает разрастаться, то могут появиться интересные эффекты:

  • Коммиты, удаляющие кучу пробелов, среди которых нужно искать реальные изменения

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

О чем кстати в книге вроде как и написано. В общем как обычно, не стоит а) вырывать тезисы из контекста б) слепо следовать правилам и предполагать, что другие так будут делать

> Коммиты, удаляющие кучу пробелов,

Включить в средстве просмотра диффов галочку "не показывать изменения пробелов и табов" ;-)

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

По мелочам есть всегда нюансы )

Читаешь какой-нибудь код, а в нем переменные типа tekushiyGod или perechisleniye. Glazovykolupyvatelnitsa.

Да лучше бы буквами y & I обозвал...

I или l? :)

Да какая разница )

Код можно поправить и даже иногда не сильно сложно... А вот если таблица называется zakaz или tranzakciya, вот это боль...

В наше время, когда для имен переменных разрешен хоть 🍅 использовать транслит...

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

Думаете тот, у кого не квадратики, а tekushiyGod будет больше обрадуется?

Переучить транслитчика на использование более-менее адекватных слов проще, чем того, кто уже привык к 1С-стилю

Ну у меня в книжке по яве 98 года очень радовался автор, что переменные можно юникодом писать.
Переучить транслитчика пишущего программу для российского применения у вас не получится. Вспоминая тот же 1С: ИНН и как будете переводить?
британским Unique Taxpayer Reference - UTR
американским ITIN (Individual Taxpayer Identification Number)
подстрочником ITN (Individual Taxpayer Number)

Вы уверены, что все команды разработчиков в холдинге на который работает ваша программа с вами согласятся?

ИНН - тот случай, когда правильнее транслитом, просто потому что "это такой термин - и-н-н", без расшифровки. Типа SATA или ISCSI

Конечно, можно писать программу везде латиницей, а ИНН кириллицей - но это совсем извращение.

Кстати, опять "следуем Единственно Верному Пути!" - если называть переменную predelnoyeZnacheniye нельзя, значит и inn нельзя, ибо ересь. Так что ли? )

Очень занимательно это читать, учитывая что автор книги давным давно полюбил ФП и пишет на Clojure:

Then, in 2010 or so, I bumped into Clojure. I had just recently read The Structure and Interpretation of Computer Programs and so was interested in playing around with a LISP derivative.

It has been 11 years now, and I feel no urge to change languages. I reckon that Clojure may be my last programming language. Oh, not that I haven't looked around. I've had some daliances with Golang, Elixr, and Kotlin, and have looked with trepidation at Haskel. I've even played with Scala and F#. I keep looking as new languages arise; but have found nothing that calls me to switch away from Clojure.

также автор книги раньше утверждал что:

The first rule of functions is that they should be small. The second is that they should be smaller than that. (…) Every function in this program was just two, or three, or four lines long. Each was transparently obvious. Each told a story. And each led you to the next in a compelling order. That’s how short your functions should be!

но если зайти к нему на Github то можно увидеть такие функции:

(defn build-character-display [width]
  (let [{:keys [segment-gap segment-length segment-height segment-width height width margin] :as context} (build-context width)
        hseg (build-horizontal-segment context)
        vseg (build-vertical-segment context)
        backslash-seg (build-backslash-segment context)
        slash-seg (build-slash-segment context)
        right-displacement (+ segment-length segment-gap)
        half-segment-width (* 0.5 segment-width)
        half-height (* 0.5 height)
        vertical-displacement (+ segment-height segment-width)
        s0 hseg
        s1 (translate-segment hseg [right-displacement 0])
        s2 vseg
        s3 backslash-seg
        s4 (translate-segment vseg [right-displacement 0])
        s5 slash-seg
        s6 (translate-segment vseg [(- width margin margin segment-width) 0])
        s7 (translate-segment hseg [0 (- half-height margin half-segment-width)])
        s8 (translate-segment hseg [right-displacement (- half-height margin half-segment-width)])
        s9 (translate-segment vseg [0 vertical-displacement])
        s10 (translate-segment slash-seg [(+ (* -0.5 width) half-segment-width margin) (- (* 0.5 height) half-segment-width margin)])
        s11 (translate-segment vseg [(+ segment-length (* 0.5 segment-gap)) vertical-displacement])
        s12 (translate-segment backslash-seg [(- (* 0.5 width) half-segment-width margin) (- (* 0.5 height) half-segment-width margin)])
        s13 (translate-segment vseg [(- width margin margin segment-width) vertical-displacement])
        s14 (translate-segment hseg [0 (- height segment-width margin margin)])
        s15 (translate-segment hseg [right-displacement (- height segment-width margin margin)])]
    {:context context
     :segments [s0 s1 s2 s3 s4 s5 s6 s7 s8 s9 s10 s11 s12 s13 s14 s15]}))

https://github.com/unclebob/skillBoard

Автор уже давно сам своим рекомендациям не следует но вы разумеется следуйте.

А в чем проблема? Рекомендации, в большинстве своем, вполне здравые. Естественно без фанатизма нужно использовать

Вера без фанатизма не бывает)

Всегда кто-то находит для себя Откровение и Единственный Верный Путь, после чего нещадно громит еретиков

А путей-то много...

скрамы с эджайлами сердечно приветствуют вас.

А можно без спойлеров?

Убийца не садовник. Читайте спокойно.

Попробую по пунктам

1Выразительность: Имя должно отвечать на все главные вопросы

Лучше, чтобы тип (или класс) отвечал на все главные вопросы, а имя (или переменная) отвечали бы на второстепенные.

Плохо: List list1;

Плохо: List activeCustomers;

Хорошо: List<ActiveCustomer> forBilling;

2 функции.

Структура кода (Сверху-Вниз - Stepdown Rule):

  • Код должен читаться как повествование, сверху вниз.

  • На верхнем уровне высокоуровневые функции (шаги алгоритма).

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

"Верхний уровень" кода оркестириует для конкретного случая данные и бизнес правила, описанные для более общих случаев.

Ну, хватит для начала.

List<ActiveCustomer> forBilling - выглядит плохо. Читая код, я должен гадать, что это? Типов я не вижу, когда читаю. А если у меня несколько сущностей для вычисления Billing, они как будут называться?

Так чистота кода неактуальна уже, код нейросеть по промптам будет переписывать будет пока тесты не начнут проходить

На brainfuck

на idris. зачем вы так быстро переключаетесь? =)

Так у вас тогда эти промпты заменят код. И получите в итоге вместо кода на формальном языке код на хаотичном языке. Тесты то хоть на формальном будут?

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

Нет, ИИ реализуют программу, согласно представленному коду. В случае ИИ пока код называют промтом.

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

Где в вашем случае можно будет узнать как работает программа?

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

Есть же сейчас методология TDD, в коде не надо разбираться, при необходимости можно перегенерировать с нуля.

Функции которые вызываются ровно один раз чтобы вызывающая их фунция уместилась в экран это не зло?

Понятные имена переменных и функций, это ближе к 1с на русском, охенно же.

Комментарии полное зло, ведь переменные и функции названы адекватно.

Да и вообще кривой код индуцирован кривыми задачами, автору видать повезло.

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

Зызы. А ещё есть две фразы, рекомендую:

Задним умом все крепки

Исторически так сложилось

Зызызы. Лучший код тот, которого нет.

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

4зы что то попёрло.

Нужно рассмотреть всё, что делает человек с точки зрения ООП, это наследование от основных базовых навыков: спать, 'потреблять', и 'выделять', к чему отнести программирование да и в целом любую деятельность, надеюсь, понятно.

Пятый будет?

Это не минусил, вроде законченная философская концепция.

Кроме того 2+2, 2*2, и 2^2 = 4, идеально же

Зы. Более если тебя спросят сколько минимум песчинок нужно для кучи песка, говори 4, это тетраэдр.

Если правильные имена 90%, то все остальное это 10%.

Мудро

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

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

>разбейте на две функции

>избегайте повторения и логических флагов в аргументах

А если эта функция применяет на 90% одинаковую обработку для разных данных?

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

Но хуже всего пассаж про комментарии

Поспорю. Пример с Point ещё хуже:

  • Добавлены никому не нужные, захламляющие код сеттеры/геттеры

  • Выбрано плохое название CalculateDistance. Расстояние - это между 2-мя точками, а то что в коде, это длина

>разбейте на две функции

>избегайте повторения и логических флагов в аргументах

А если эта функция применяет на 90% одинаковую обработку для разных данных?

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

А если структура этого кода

  • некоторые действия (1)

  • операции, зависящие от флага, например, обращение по сети (2)

  • некоторые действия, зависящие от переменных из (1) и (2)

Здесь иногда легко не выделишь функции, потому что может быть куча контекста.

Не возвращайте null! Это источник NullReferenceException ... используйте Nullable для значимых типов, применяйте паттерн Null Object.

Скорее всего подразумевалось противопоставление: "НЕ используйте Nullable, а применяйте паттерн Null Object".

Так же в контексте C# хотелось бы оговорки про nullability.

Используйте исключения, а не коды ошибок.

Все чаще встречаю проекты, где тем или иным образом пытаются делать свои решения в стиле растового Result<TResult, TErr> для обработки возможных/ожидаемых ошибок, а исключения - оставлять лишь фатальным, которые ловить сильно выше с целью только залоггировать. Как ни крути, но исключения - это дорогое удовольствие, подход Errors are values идет в массы.

Как по мне, то во всяких валидациях Result<> идеален. Сразу виден весь путь. Не надо разбираться в каком случае какой эксепшен должен быть, где он ловится и обрабатывается. Ну и конечно производительность.

Плюсов много, да, но не соглашусь, что решение идеально.

Объединение нескольких (списков типов/discriminated unions) ошибок в единственный тип при пробросе ошибок наверх - это боль и туча бойлерплейта маппинга типов, а рефакторинг в таких условиях - дабл-боль. А если еще и вручную проверку результата нужно делать (отстствует аналог растового ?) - трипл-боль, код раздувается огромным количеством шума чуть ли не в разы (получи результат => проверь результат и подними ошибку => распакуй результат).

Обработка исключений этих проблем лишина, т.к. появляется только там, где это имеет смысл, никаких обвязок для проталкивания ошибки наверх и "запаковки типов" не нужно => нет кода - нет и необходимости его поддерживать.

Избегайте дезинформации:
Не используйте accountList для переменной типа Account[] (это не список). Лучше accounts или accountGroup.

Лучше называйте так как называется у пма в спеке. Иначе потом цирк будет полный

Закомментированный код: Удаляйте его! Системы контроля версий хранят историю.

Какая система контроля версий подходит для работы с LaTeX без серверов?

А какая подходит для работы с LaTeX без редакторов, прямо в браузере?

Спасибо.

TryParse по-моему уже нарушает упомянутые немного ранее правила про out аргументы и возврат нескольких значений, при этом рекомендуется его использовать.

Судя по всему, чтиво не особо стоящее: банальности пополам со спорностями, а многое откровенно заслуживает посыла в жопу.

Плохо: int d; // elapsed time in days
Хорошо: int elapsedTimeInDays;

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

Флаги как аргументы - ЗЛО! (Process(bool isAdmin)) - Это явный признак, что функция делает два разных дела! Разбейте на две: ProcessAdmin(), ProcessUser()

Точно так. CreateWindow(), CreateWindowWithBorder(), CreateWindowWithBorderThatUserCanDrag(), CreateWindowWithBorderThatUserCanDragButTheMinimalSizeOfTheWindowIs640By480Pixels(), и т. д., и т. п., для каждой из миллиона возможных комбинаций того, что по-нормальному флагами делают.

Output-параметры (out, ref) - Еще большее зло! Они запутывают и нарушают поток чтения. Возвращайте кортежи или маленькие объекты-результаты.

Особенно когда в огромном массиве чего-то надо поменять чего-то. Вернёмте, друзья, маленький объект-результат с огромной копией исходного массива, в которой отличаются три элемента.

Хорошо:
public class ReservationRequest
{
public DateTime Start { get; set; }

Особенно в языках, где на каждый чих надо выписывать все эти "public бублик static всратик void zoid истероид".

Закомментированный код: Удаляйте его! Системы контроля версий хранят историю.

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

Выравнивание: Избегайте выравнивания переменных по типу или значению. Оно создаёт ложный акцент и сложно поддерживается.

Отличный способ форматирования, особенно после того, как отключишь сраные линтеры, чтоб не вопили красным "срань господня! йа нашол больше одного пробела подряд! срочно сжэч!"

accounts

Адское зло, когда потом тебе идеха начинает подсовывать переменные отличающиеся одним символом. Хорошо, если система типов бдит, а если ее нет?

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

А то начитаются этих вырванных правил и бездумно применяют повсюду. Да ещё и других этому же учат. Особенно с этим SRP (неправильно понятым, как правило) как святым граалем носятся.

Почти постоянно пишут, что используют «чистый» код. Интересно, есть ли кто напишет, что использует «грязный» код, например, в своем резюме?

Я бы написал. Ибо KISS рулит...

Методы и функции

Маленькие, хорошо организованные методы это главное чистого кода!

  1. МАЛЕНЬКИЕ! И ещё раз МАЛЕНЬКИЕ!

    • Идеал: Не длиннее 20 строк. Часто 3-4 строки.

    • Правило экрана: Функция должна полностью помещаться на одном экране без прокрутки.

У меня привитый в детстве фортран головного мозга, разделяю функции в основном если они могут использоваться повторно. Иначе закопаешься в их названиях. Это про C++. В крайнем случае выношу вспомогательные операции непосредственно в исходнике перед основной функцией. Даю какой-нибудь префикс типа одинарного или двойного подчёркивания, чтобы знать, что у неё нет объявления в заголовочных файлах, одноразовая, используется только здесь и сейчас. Может для этого существуют другие практики, не знаю.

Как я понимаю в современных плюсах добавлен хороший механизм лямбда выражений. "И нашим, и вашим".

подчеркивания перед именами а особенно __двойные или __двусторонние__ подчеркивания - это путь в ад. Только вы знаете что они в вашем проекте означают.

Согласен, но мои хоббийные проекты не предполагают совместной разработки или публичности.

Анализ текста: написан ИИ или человеком?

Этот текст, скорее всего, написан ИИ (например, ChatGPT или другим LLM), но с высокой долей редактуры или адаптации человеком.

Статья, написанная ИИ про книгу 2008 года от инфоцигана Боба. Хабра, тебе там ок?

Когда делаете скриншот окна, зажмите альт. Тогда у окна не будет тени (-2 см пустого места по периметру).

Это сервис специальный, а не снимок экрана.

Методы и функции

Маленькие, хорошо организованные методы это главное чистого кода!

  1. МАЛЕНЬКИЕ! И ещё раз МАЛЕНЬКИЕ!

    • Идеал: Не длиннее 20 строк. Часто 3-4 строки.

    • Правило экрана: Функция должна полностью помещаться на одном экране без прокрутки.

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

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

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

Подождите! А почему мы не хотим всё это хозяйство как-то автоматизировать? Почему мы не можем несколько тысяч полей пройти в цикле? Откуда, кстати, взялись тысячи полей?

Чтобы написать цикл, нужно всё равно каждое конкретное значение откуда-то как-то взять.

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

Откуда, кстати, взялись тысячи полей?

Например, опросили тысячу разных устройств по разным API. Условно, хотим отдать конфигурацию своего компьютера по запросу SNMP (хотя в SNMP есть кое-какая иерархия, поэтому пример не очень точный, зато понятный).

Обработка ошибок

Ошибки - часть жизни ПО. Обрабатывайте их чисто:

Чисто или часто? ;-)

Используйте исключения, а не коды ошибок.

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

Наверное, существуют две школы: школа любителей исключений и школа любителей кодов ошибок.

Сначала пишите Try-Catch-Finally: Обрабатывайте код, который может выбросить исключение, блоком try. Обрабатывайте конкретные исключения в catch. Освобождайте ресурсы в finally.

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

А, ведь, можно пойти ещё дальше и, вообще, весь код построить на исключениях! А что? Удобно! Дошёл до конца списка — выкинул исключение. Можно было бы даже из вложенных циклов выходить вместо break и с подробным описанием уровня, с которого выскочили.

Не возвращайте null! Это источник NullReferenceException (для C#, аналогично в других языках). Возвращайте пустые коллекции (Enumerable.Empty(), new List()), используйте Nullable<T> для значимых типов, применяйте паттерн Null Object.

Эххх... Вот, во времена засилья C/C++ очень любили всё сравнивать с NULL. Автор книги, наверное, перебрал с C/C++. Впрочем, вопрос интересный. Мне кажется, что "пустой объект" отдельного ото всех типа (как в Python) — это хорошая идея. Думаю, здесь есть, что обсудить.

Не передавайте null! Это смещает ответственность за проверку на вызывающего. Бросайте ArgumentNullException в начале метода, если null недопустим.

И что мы должны сделать, если такое исключение выкинется?

А, ведь, можно пойти ещё дальше и, вообще, весь код построить на исключениях! А что? Удобно! Дошёл до конца списка — выкинул исключение. Можно было бы даже из вложенных циклов выходить вместо break и с подробным описанием уровня, с которого выскочили.

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

Я не иронизирую, а говорю совершенно серьёзно. Пытаюсь представить.

Классы

Ох, уж, @cupraer разошёлся бы...

Принцип единственной ответственности (Single Responsibility Principle - SRP): У класса должна быть только одна причина для изменения. Если класс делает слишком много, его нужно разбить.
Признаки нарушения SRP: Много несвязанных методов/полей, частые изменения в разных местах класса по разным причинам, большой размер.

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

А ещё есть такой вопрос: а нужен ли здесь обязательно какой-нибудь класс?

Инкапсуляция: Скрывайте данные и детали реализации! Делайте поля приватными. Предоставляйте доступ через методы / свойства. Ослабляйте уровень доступа только при явной необходимости.

Все так советуют делать. Вроде бы, азы ООП. Напоминает одну детскую книжку:

– Я умею кое-что получше.

– Все говорят «я умею кое-что получше», – засмеялись ребята.

– Правду говорю!

– Все говорят «правду говорю!»

– Да ну вас!

– Все говорят «да ну вас!»

Композиция прежде наследования (Composition over Inheritance): Наследование создаёт сильную связь между классами. Часто композиция (включение одного класса в другой как поле) + интерфейсы дают больше гибкости.

Наверное, в таком стиле (как в приводимом примере) можно многое переписать...

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

Люди! Зачем вы плюсуете ИИшные статьи, а? Себе же хуже делаете

А это ИИ определил, что статья ИИшная?

Нет, ЕИ

Если вы настаиваете, что сами писали статью, то у меня вопрос - зачем вставлять картинки с 1-2 строчками кода? Особенно иронично это в разделе про избыточные комментарии )

А что именно Вас беспокоит?

Если бы Вас интересовало бы существо дела, то тут было бы оно из двух: либо автор книги (Роберт Мартин?) где-то здорово промахнулся, и чей-то опыт об этом ярко свидетельствует, либо где-то искажена мысль самого автора (при изложении). Наша задача в чём заключается? В том, чтобы лучше программировать.

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

Не все пересказы одинаково бесполезны. ;-)

Не возвращайте null! Это источник NullReferenceException (для C#, аналогично в других языках).

Как .NET-программист говорю - это очень херовый совет и плохая практика. null позволяет сразу понять, что функция/метод сработали неправильно и что надо что-то поменять. А когда функция возвращает пустой список то хрен поймёшь - это функция отработала неправильно, или ты не те данные на входе подал.

Если использовать этот совет в связке с "бросайте исключение" (это не призыв к действию), то и без null-a станет понятно, что функция сработала неправильно.

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

Публикации