Для большей безопасности. При локе на this нет гарантий, что кто-то ещё не решит также использовать ваш объект в качестве ключа, что может привести к внезапным дедлокам.
Когда придумаешь хорошую абстракцию, которая хорошо подходит к обоим функциям. )
То есть не всегда или, как минимум, не сразу.
Это лишнее по вашему?
Зависит от контекста и от наполнения этих самых строк. Собственно, в этом и была моя изначальная мысль — всё не так просто. При этом статья не приводит примеров, где надо делить, где не надо, а лишь говорит «маленькие функции — хорошо». Отличный посыл новичкам, которые ринутся выносить приват методы на каждый чих, ведь так Мартин сказал.
А можно сделать одну функцию из 20 строк и 20 функций по 50+ строк.
Тут, кстати, занятный вопрос — а функция, у которой внутри 50 функций на 20 строк, это всё ещё функция на 1000 строк?
Если у нас есть дублирование некоего кусочка кода в двух функциях, то его вот обязательно выносить в отдельную? Всегда?
Вопрос номер два — если у нас вообще нет дублирования, зачем захламлять класс кучей приватных функций, которые используются в нашей одной большой?
А вот если взглянуть на это как на непрерывную шкалу, то оно превращается в «слишком много отвественности» и «достаточно мало».
Абсолютно согласен.
Если же воспринимать эти книги вот так вот, отрицая их, потому что с первого раза не получилось, то с мертвой точки оно не сдвинется естественно.
Я воспринимаю не «эти книги», я воспринимаю эту конкретную книгу и этого конкретного автора. Есть куда более полезные и сдержанные в своей подаче материалы, а в тысячный раз обсасывать «чистый код» мне лично не хочется. Не исключаю, что я в меньшинстве.
Возможно, я старый и пессимистичный, но я понимаю смысла подобных статей. Автор показывает простейшие примеры на уровне «давайте не смешивать генерацию html вёрстки с высокоуровневой генерацией тегов» и рассказывает, что, внезапно, понятные функции лучше непонятных.
При этом не проводится разбор обратных сценариев и нюансов: а когда, собственно, имеет смысл делать большие функции и чем мы жертвуем (опуская производительность), разбивая и вынося подсчёт высоты в отдельный метод. Каким образом и почему в продакшне таки появляются огромные функции? Неужели, все, кто их пишут — некомпетентны и не читали Clean Code?
Пункт про размер функции непонятно как работает со вложенными функциями, но я подозреваю, что в основном языке автора их на тот момент не было.
Пункт про количество аргументов — абсурд, ведь любой набор из Х аргументов эквивалентен объекту с Х полями. Так что, станет лучше, если мы везде вынесем DTO?
Если читать книгу Мартина новичком и воспринимать буквально, на мой взгляд, хорошего не выйдет. А если вы опытный разработчик и понимаете, что картина не всегда такая простая и однозначная, зачем вам эта книга?
Искренне не понимаю, откуда на медиуме набралось 3к лайков и здесь 40 плюсов. После прочтения статьи появилось чувство не детального и обстоятельного разбора, а чего-то маркетингового с кучей обтекаемых и абстрактных формулировок.
человек, который выступает за гендерное равноправие не может быть сексистом
А с чего, позвольте, взялся «человек который выступает за гендерное равенство»? Я даже не буду спрашивать, каким путём достигается это равенство, подождём с этим.
Вернёмся к утверждению: «кто-то осознаёт неравноправное положение, но не считает его угнетённым». Т.е. человек считает, что положение неравноправное, но в плюс, а не минус. При этом он так же считает его правильным. Он сексист?
Проверяем не вызвался ли метод add, а появился ли пользователь в «базе» после вызова сервиса
Да, такое делали, в случае .NET просто через EF InMemory. Хороший подход и, в целом, более правильный, на мой взгляд.
Такие случаи бывают когда сложные условия, циклы.
Были куски логики посложнее, но там по итогу всё переписывалось на легковесную state machine и уже она тестилась. Традиционное «закинем моки и проверим вызовы» показалось не оптимальным.
Как пример: в зависимости от того, обращался пользователь ранее к сервису или нет, надо было вести себя по-разному. Сам вызов метода на получение информации о предыдущих обращениях не тестили, а вот логику в виде условной функции (currentState, userRequest) -> newState покрыли на ура. Пока что коллегам нравится.
Очень похоже на формальную верификацию, так что вряд ли с минимальными усилиями получится
Вот, у меня такие же мысли. Звучит хорошо, но на практике не так легко.
С другой стороны, на каком-нибудь gherkin в секции given можно написать что-то вроде «user with email test@example.com is(n't) registered», но нужно будет написать хэндлер для этого паттерна, приводящий систему в нужное состояние.
К сожалению, не работал с gherkin и вообще BDD не щупал на реальных проектах. Не исключаю, что в итоге оно может оказаться ещё более затратным, чем «тупой» тест с моками.
Спасибо. Именно такой вариант я наблюдал и практиковал у себя.
Что заметил из интересного:
Приходится заглядывать в реализацию, дабы знать, какой именно метод IUserRepository вызывается и какой надо мокать. Когда классы разрастаются, это начинает напрягать и концептуально я не сторонник тестировать, зная реализацию (classical TDD мне по душе больше, чем mockist). В принципе, решается дроблением Repository на более атомарные операции.
Если вы используете строгие моки, то вы также убеждаетесь, что ничего кроме этих зависимостей не вызвали. Звучит неплохо, но на практике у нас вылилось в невероятно хрупкие тесты. Без строгих моков тоже не идеально, но я лично готов это стерпеть.
При увеличении количества вызываемых методов и классов, сетап моков становится сложнее и сложнее. Частично решается так же, как в пункте 1, но не до конца.
Признаться, не уверен, стоит ли действительно тестировать такую логику. Я не припомню ни одного случая, когда у нас вызовы функций исчезали или дублировались, при этом написание таких тестов в более сложной системе это не пара минут.
Как итог, я предпочитаю такие тесты в принципе не писать. Оценить импакт с научной точки зрения сложно, но субъективно особой пользы я от них не видел.
Что меня очень интересует, это то, можно ли с минимальными усилиями описать спецификацию «мы делаем Б и В (publish, add) только если условие А истинно, в противном случае возвращаем ошибку». То есть, вместо того, чтобы императивно проверять, что и когда вызывается, выразить правила декларативно с гарантией того, что они не нарушатся разработчиком случайно.
Из того, что встречал — вместо непосредственно выполнения этих действий вернуть структуру, описывающую, что и как делать, наподобие AST: blog.ploeh.dk/2017/07/31/combining-free-monads-in-f
Правда, и ASТ также придётся валидировать на корректность тестами.
Вопрос того, насколько с этим удобно работать конкретно в .NET на C# для меня пока открыт.
В одном проекте будет нормой минимальный набор юнит-тестов, в другом надо будет покрывать почти все.
Абсолютно согласен. К сожалению, в индустрии защитить мнение «мы не будем писать юнит тесты т.к. конкретно здесь они не оправданны» куда сложнее, чем обратное. В итоге получается некий карго-культ, когда тесты пишутся потому что циферки красивые и «смотрите, вот у нас несколько сотен тестов, мы серьёзные квалифицированные люди».
P.S. А дальше извините, у меня работа а я и так уже три часа тут торчу.
Разумеется. Если будет время и желание, я бы с удовольствием обсудил это подробнее, т.к. тема лёгких и полезных юнит тестов очень интересна, особенно в сравнении чистых функций и алгоритмов против типичного энтерпрайза.
Во многом согласен. Возможно, мне не повезло видеть хороших юнит тестов, но в типичной enterprise LoB разработке они выглядели именно так, как описывает автор — хрупкими, не очень полезными и достаточно дорогими в разработке.
Moreover, я уже несколько лет веду неформальную личную статистику по багам, их причинам и «какой тест мог бы поймать этот баг». Багов, которые были бы легко пойманы юнит тестами замечал крайне мало. Разумеется, обратную ситуацию тоже рассматривал — смотрел на юнит тесты и прикидывал, а что они поймали бы. Зачастую это ошибки в роде «ну, если разработчик забудет вызвать функцию, то мы это поймаем».
С другой стороны, это сильно зависит от домена и характера разработки. Когда я ради интереса набрасывал простейший лексер в относительно ФП стиле с чистыми функциями, тестировать его было одно удовольствие. Никаких километровых моков, простые чистые функции input-output. Можно пойти дальше и попробовать описать некоторые свойства системы не в виде простого юнит-теста, а в виде property-based testing. Если пойти и ещё дальше, то вместо тестов у нас появятся типы и compile-time доказательства корректности программы.
(это конечно не best practices, когда сначала пишут тесты, а потом код)
Почему же? Есть целая методология под это — Test Driven Development.
Я отдельные модули по одному пишу
Приведите, пожалуйста, парочку примеров.
Вот, скажем, стандартный пример из моей практики: приходит ХТТП реквест на регистрацию, надо сделать следующие действия (happy path):
1. Сходить в базу проверить, нет ли пользователя.
2. Создать пользователя в базе
3. Закинуть в message bus сообщение, что новый пользователь был создан
4. Ответить 200 клиенту
Предположим, мы вынесли эту логику на некий бизнес-слой, т.е. у нас есть функция SignUpUser, которая внутри вот это всё делает. Что и как мы будем тестить?
Ок, так как правильно в случае трансгендерного Криса — Chris was angry или Chris were angry?
Я бы использовал was, потому что they тут в предложении даже не участвует. Если участвует — множественное. Chris was angry. It's not the first time they were.
Программисты визуалы, им нафиг ваши созвоны не сдались.
Во-первых, крайне смелое обобщение. Во-вторых, смотря что понимать под созвоном. Митинги на часы мне не сдались не потому что я, как вы говорите, «визуал», а потому что мне больно от их КПД — 90% времени приходится выслушивать кого-то, попивая чай и не особо вникая в тему.
Тем не менее, быстрый созвон на 15 минут, лично для меня, в разы эффективнее и продуктивнее переписки. Вот не могу я улавливать/объяснять текстом так же хорошо, как голосом. Если это что-то более-менее формальное — после обсуждения подводим итоги и закидываем minutes, дабы не потерять информацию.
Признаться, это самый безобидный пример. Для меня they даже как-то более естественно, потому что неизвестный пол не значит мужской (и женский тоже не значит, впрочем). Сам использую singular they в речи более восьми лет и не чувствовал, чтобы он был forced. Более того, как уже сказали, конструкция существует давно — это не что-то, выдуманное на волне толерантности.
Остальные замены внушают тихий ужас. Не только своей бессмысленностью, но и уверенностью инициаторов в том, что они как-то помогают. Есть ещё вариант, что самим компаниям глубоко всё равно и это исключительно ради ПР, но и он не радует.
Не придирки ради, разве не clustered index определяет то, является ли таблица кучей? Соответственно, можно создать таблицу с PK, но без индекса и наоборот.
my 2 cents:
Много лет придерживался и до сих придерживаюсь мнения, что многие статьи и книги Боба крайне категоричны и, местами, откровенно опасны для новичков. С другой стороны, опытному разработчику они не сильно и нужны. Куда больше они подходят для инициации обсуждения и холиворов.
rant
А утверждение Боба, что типизация не нужна, так как есть юнит тесты вызывает у меня целую бурю не очень хороших эмоций.
Тут рядом упоминали Code Complete — поддержу. Хорошая, обстоятельная книга, перекосов и абсолютизма не припомню.
Одна из причин, почему ООП в целом выглядит хорошо — его часто противопоставляют спагетти на 4000 строчек. Крайне сложно утверждать, что между «красивой иерархией классов» и «монстром на 4000 строк» ты выберешь монстра. Однако, это ложная дихотомия.
Во-первых, существует то же ФП, которое местами показывает очень интересные результаты и вообще функции это классы для бедных и наоборот. Во-вторых, мейнстрим ООП на «сервисах» это по сути glorified процедурное программирование.
Очень хорошее и в некотором смысле inspiring выступление по ООП можно наблюдать у Sandi Metz: www.youtube.com/watch?v=OMPfEXIlTVE
Что интересно, в процессе разбиения получился набор более мелких классов, каждый из которых старается выполнять одну вещь и при этом не хранить состояния. Что, внезапно, эквивалентно передаче функций без замыканий.
Также отмечу фрагмент про наследование и его опасность, мой личный опыт в целом подтверждает.
А вот если оставить ситуацию по умолчанию, то черные вообще скорее всего не смогут претендовать на эти позиции.
С чего бы это? У нас 5 вакансий, в выборке 10 белых и 1 чёрный. Кто этому чёрному мешает соревноваться?
Более того, возникает ещё один интересный вопрос — а зачем нам в штате чёрный, если он проигрывает борьбу без квот? Почему наличие работника с определённым цветом кожи является преимуществом (кроме virtue signalling)? Так же, если говорим о расах, то давайте поговорим и об азиатах, а ещё вспомним национальности. Я искренне не вижу, как эта модель работает и производит что-либо продуктивное.
То есть не всегда или, как минимум, не сразу.
Зависит от контекста и от наполнения этих самых строк. Собственно, в этом и была моя изначальная мысль — всё не так просто. При этом статья не приводит примеров, где надо делить, где не надо, а лишь говорит «маленькие функции — хорошо». Отличный посыл новичкам, которые ринутся выносить приват методы на каждый чих, ведь так Мартин сказал.
Тут, кстати, занятный вопрос — а функция, у которой внутри 50 функций на 20 строк, это всё ещё функция на 1000 строк?
Если у нас есть дублирование некоего кусочка кода в двух функциях, то его вот обязательно выносить в отдельную? Всегда?
Вопрос номер два — если у нас вообще нет дублирования, зачем захламлять класс кучей приватных функций, которые используются в нашей одной большой?
Абсолютно согласен.
Я воспринимаю не «эти книги», я воспринимаю эту конкретную книгу и этого конкретного автора. Есть куда более полезные и сдержанные в своей подаче материалы, а в тысячный раз обсасывать «чистый код» мне лично не хочется. Не исключаю, что я в меньшинстве.
При этом не проводится разбор обратных сценариев и нюансов: а когда, собственно, имеет смысл делать большие функции и чем мы жертвуем (опуская производительность), разбивая и вынося подсчёт высоты в отдельный метод. Каким образом и почему в продакшне таки появляются огромные функции? Неужели, все, кто их пишут — некомпетентны и не читали Clean Code?
Пункт про размер функции непонятно как работает со вложенными функциями, но я подозреваю, что в основном языке автора их на тот момент не было.
Пункт про количество аргументов — абсурд, ведь любой набор из Х аргументов эквивалентен объекту с Х полями. Так что, станет лучше, если мы везде вынесем DTO?
Если читать книгу Мартина новичком и воспринимать буквально, на мой взгляд, хорошего не выйдет. А если вы опытный разработчик и понимаете, что картина не всегда такая простая и однозначная, зачем вам эта книга?
Искренне не понимаю, откуда на медиуме набралось 3к лайков и здесь 40 плюсов. После прочтения статьи появилось чувство не детального и обстоятельного разбора, а чего-то маркетингового с кучей обтекаемых и абстрактных формулировок.
А с чего, позвольте, взялся «человек который выступает за гендерное равенство»? Я даже не буду спрашивать, каким путём достигается это равенство, подождём с этим.
Вернёмся к утверждению: «кто-то осознаёт неравноправное положение, но не считает его угнетённым». Т.е. человек считает, что положение неравноправное, но в плюс, а не минус. При этом он так же считает его правильным. Он сексист?
Да, такое делали, в случае .NET просто через EF InMemory. Хороший подход и, в целом, более правильный, на мой взгляд.
Были куски логики посложнее, но там по итогу всё переписывалось на легковесную state machine и уже она тестилась. Традиционное «закинем моки и проверим вызовы» показалось не оптимальным.
Как пример: в зависимости от того, обращался пользователь ранее к сервису или нет, надо было вести себя по-разному. Сам вызов метода на получение информации о предыдущих обращениях не тестили, а вот логику в виде условной функции (currentState, userRequest) -> newState покрыли на ура. Пока что коллегам нравится.
Вот, у меня такие же мысли. Звучит хорошо, но на практике не так легко.
К сожалению, не работал с gherkin и вообще BDD не щупал на реальных проектах. Не исключаю, что в итоге оно может оказаться ещё более затратным, чем «тупой» тест с моками.
Что заметил из интересного:
Как итог, я предпочитаю такие тесты в принципе не писать. Оценить импакт с научной точки зрения сложно, но субъективно особой пользы я от них не видел.
Что меня очень интересует, это то, можно ли с минимальными усилиями описать спецификацию «мы делаем Б и В (publish, add) только если условие А истинно, в противном случае возвращаем ошибку». То есть, вместо того, чтобы императивно проверять, что и когда вызывается, выразить правила декларативно с гарантией того, что они не нарушатся разработчиком случайно.
Из того, что встречал — вместо непосредственно выполнения этих действий вернуть структуру, описывающую, что и как делать, наподобие AST:
blog.ploeh.dk/2017/07/31/combining-free-monads-in-f
Правда, и ASТ также придётся валидировать на корректность тестами.
Вопрос того, насколько с этим удобно работать конкретно в .NET на C# для меня пока открыт.
Абсолютно согласен. К сожалению, в индустрии защитить мнение «мы не будем писать юнит тесты т.к. конкретно здесь они не оправданны» куда сложнее, чем обратное. В итоге получается некий карго-культ, когда тесты пишутся потому что циферки красивые и «смотрите, вот у нас несколько сотен тестов, мы серьёзные квалифицированные люди».
Разумеется. Если будет время и желание, я бы с удовольствием обсудил это подробнее, т.к. тема лёгких и полезных юнит тестов очень интересна, особенно в сравнении чистых функций и алгоритмов против типичного энтерпрайза.
Moreover, я уже несколько лет веду неформальную личную статистику по багам, их причинам и «какой тест мог бы поймать этот баг». Багов, которые были бы легко пойманы юнит тестами замечал крайне мало. Разумеется, обратную ситуацию тоже рассматривал — смотрел на юнит тесты и прикидывал, а что они поймали бы. Зачастую это ошибки в роде «ну, если разработчик забудет вызвать функцию, то мы это поймаем».
С другой стороны, это сильно зависит от домена и характера разработки. Когда я ради интереса набрасывал простейший лексер в относительно ФП стиле с чистыми функциями, тестировать его было одно удовольствие. Никаких километровых моков, простые чистые функции input-output. Можно пойти дальше и попробовать описать некоторые свойства системы не в виде простого юнит-теста, а в виде property-based testing. Если пойти и ещё дальше, то вместо тестов у нас появятся типы и compile-time доказательства корректности программы.
Почему же? Есть целая методология под это — Test Driven Development.
Приведите, пожалуйста, парочку примеров.
Вот, скажем, стандартный пример из моей практики: приходит ХТТП реквест на регистрацию, надо сделать следующие действия (happy path):
1. Сходить в базу проверить, нет ли пользователя.
2. Создать пользователя в базе
3. Закинуть в message bus сообщение, что новый пользователь был создан
4. Ответить 200 клиенту
Предположим, мы вынесли эту логику на некий бизнес-слой, т.е. у нас есть функция SignUpUser, которая внутри вот это всё делает. Что и как мы будем тестить?
Я бы использовал was, потому что they тут в предложении даже не участвует. Если участвует — множественное. Chris was angry. It's not the first time they were.
В каких контекстах относиться? Я определённо не осилю отношения с mtf трансом, особенно интимные. Надеюсь, это за дискриминацию пока что не считается.
Эти вещи кажутся более важными, imo.
Во-первых, крайне смелое обобщение. Во-вторых, смотря что понимать под созвоном. Митинги на часы мне не сдались не потому что я, как вы говорите, «визуал», а потому что мне больно от их КПД — 90% времени приходится выслушивать кого-то, попивая чай и не особо вникая в тему.
Тем не менее, быстрый созвон на 15 минут, лично для меня, в разы эффективнее и продуктивнее переписки. Вот не могу я улавливать/объяснять текстом так же хорошо, как голосом. Если это что-то более-менее формальное — после обсуждения подводим итоги и закидываем minutes, дабы не потерять информацию.
Остальные замены внушают тихий ужас. Не только своей бессмысленностью, но и уверенностью инициаторов в том, что они как-то помогают. Есть ещё вариант, что самим компаниям глубоко всё равно и это исключительно ради ПР, но и он не радует.
Интересно, не накинулись ли ещё на mankind.
Много лет придерживался и до сих придерживаюсь мнения, что многие статьи и книги Боба крайне категоричны и, местами, откровенно опасны для новичков. С другой стороны, опытному разработчику они не сильно и нужны. Куда больше они подходят для инициации обсуждения и холиворов.
Тут рядом упоминали Code Complete — поддержу. Хорошая, обстоятельная книга, перекосов и абсолютизма не припомню.
Одна из причин, почему ООП в целом выглядит хорошо — его часто противопоставляют спагетти на 4000 строчек. Крайне сложно утверждать, что между «красивой иерархией классов» и «монстром на 4000 строк» ты выберешь монстра. Однако, это ложная дихотомия.
Во-первых, существует то же ФП, которое местами показывает очень интересные результаты и вообще функции это классы для бедных и наоборот. Во-вторых, мейнстрим ООП на «сервисах» это по сути glorified процедурное программирование.
Очень хорошее и в некотором смысле inspiring выступление по ООП можно наблюдать у Sandi Metz:
www.youtube.com/watch?v=OMPfEXIlTVE
Что интересно, в процессе разбиения получился набор более мелких классов, каждый из которых старается выполнять одну вещь и при этом не хранить состояния. Что, внезапно, эквивалентно передаче функций без замыканий.
Также отмечу фрагмент про наследование и его опасность, мой личный опыт в целом подтверждает.
С чего бы это? У нас 5 вакансий, в выборке 10 белых и 1 чёрный. Кто этому чёрному мешает соревноваться?
Более того, возникает ещё один интересный вопрос — а зачем нам в штате чёрный, если он проигрывает борьбу без квот? Почему наличие работника с определённым цветом кожи является преимуществом (кроме virtue signalling)? Так же, если говорим о расах, то давайте поговорим и об азиатах, а ещё вспомним национальности. Я искренне не вижу, как эта модель работает и производит что-либо продуктивное.