Родителей же у нас нет, все дети России теперь сами по себе, только государство о них думает.
Меня вот в формулировке этого «закона» тоже интересует данный момент. Почему это государство решает, что можно и что нельзя смотреть моему ребенку? Если я не хочу, чтобы ребенок что-то смотрел, я установлю родительский контроль.
И почему по телевизору можно показывать сериалы про бандюков и домдва с предупреждением, мол до 16 нини, а в интернетах совсем ничего вообще нельзя (окромя восхваления царя-батюшки и господа Б-га, конечно)?
ЗЫ. Я понимаю, для чего создавался это закон, я говорю о его формулировке.
Если предполагаемая реализация функционала не сможет быть подвергнута рефакторингу, то эта реализация тривиальна и тесты на неё не требуются
Да, так вернее. Тут сразу отражается фат того, что у функции уже есть предполагаемая реализация, которая предельно проста.
Но все же я склонен к тому, что тривиальность каждый определяет по себе и по своему «уровню уверенности».
Есть еще такая фраза: «Не верь тесту, который никогда не видел упавшим». Если править тесты после правки кода, то тест нельзя будет считать рабочим, т.к. он был подогнан под требования кода, а не наоборот. Я в своей практике столкнулся с такой проблемой. Искренне считал, что функция (крайне не тривиальная) работает корректно, т.к. тест на нее проходил. Но беда была в том, что тест писался после некоторых экспериментов и был подогнан под работу функции. В результате я заработал себе головную боль от поисков бага.
Я в другой вселенной живу. Постоянно такие ситуации. Ничто на века не пишется. И код подсказывает тоже, что и как использовать надо и что может не так называться, как думали заранее.
Ничто не пишется на века, да. Но никогда ни в одном проекте я не встречал ситуации, чтобы кто-то менял поведение функции на нечто совершенно с предыдущим поведением не связанное.
Тесты пишутся с нуля до кода, тесты правятся после падений. Вот так логично.
Есть 2 ситуации, в которых правится код: Рефакторинг/оптимизация и добавление/изменение функционала. В первом случае правка тестов не нужна, т.к. требования к коду не меняются. Во втором правка кода непременно должна начаться с изменения тестов, т.к. это стандартный цикл тест — код — рефакторинг — тест — … итд.
Выше задавали вопрос о том, как понять, является ли функция тривиальной или нет. В дискуссии у меня родился ответ: если функцию при ее текущем функционале нельзя подвергнуть рефакторингу, она тривиальна.
Писали функцию вроде «GetPersonFullName», а потом, например, так случилось, что это стало идентификатором машины клиента.
Вот это и есть наобум. Как в какой вселенной может случиться такая ситуация?
Поэтому, когда вы пишете тест перед написанием кода функции (какого-то ее функционала) — это одно. А когда вы начинаете переделывать функцию и начинаете с правки теста — это другое.
Что за двойные стандарты? Если уж применяем TDD, то будьте добры начинать правку кода с тестов. А то получается, что делать допущения в моем случае — богомерзко, а в вашем — ничего страшного.
Например, на вашу фукнцию уже с десяток тестов, причем косвенных. Те, которые там где-то интеграционно как вы писали проверяют и эту примитивную функцию. У там неявно тест подразумевает, что функция вернет «John Doe», а не «Doe John Doe». Меняя один тест, который, как вам кажется, тестирует нужный функционал (или дописывая ненаписанный тест), вы все тесты делаете противоречивыми. Т.е. разные утверждения (тесты) противоречат друг другу.
Омфг. Вот у меня есть тест, проверяющий правильность вывода списка пользователей. Он проверяет, что выводится имя и фамилия. До этого я «ручками» вставлял свойства «first_name» и «last_name». Со временем имена пользователей начали возникать то в одном, то в другом месте, и я, чтобы не нарушать принцип DRY, написал функцию-хелпер full_name. По факту эта функция проверяется во всех местах, где проверяется вывод пользователя. Если я напишу на нее отдельный тест, то это не отменит того, что она будет косвенно проверяться в остальных местах. Если я изменю эту функцию, то у меня завалится на 1 тест больше. Если я поменяю какой-то тест, то у меня станет на 1 противоречивый тест больше. Вот и вся разница.
Повторюсь в 100й раз, вы впадаете в крайности, считая программиста по-умолчанию идиотом, а тесты — панацеей. Приведенные вами примеры — эта абсолютная синтетика, имеющая с реальностью мало общего.
Открываем файл с тестами класса, ctrl+f, имя функции. Думаю, в пару секунд уложились. А теперь предположим, сколько времени займет написание + постоянное выполнение кучи ненужных тестов.
не вижу бОльшей вины другого разработчика, который правит функцию без теста, чем того, кто не написал тест при написании функции сразу.
Я вижу. Мы тут все же TDD занимаемся, а значит при правке нужно первым делом править тест. Теста нет? (Функция элементарна, он ни к чему) Напиши тест, если новый требуемый функционал не тривиален. Не нужно бросаться в крайности.
Мозг не причем. Функция пишется не для самосуществования. Зачем-то используется. И разработчик может увидеть в результате рефакторинга, что по сути, функция делает что-то другое. И не правильно называется.
Это, опять же, не refActoring, а refUcktoring. Т.е. порча кода. Если какому-то разработчику вздумалось переименовать функцию или изменить ее функционал наобум, то ему хватит ума и удалить тест от старой функции и написать новый. Давайте для начала предположим, что не все разработчики идиоты, и не будем разрабатывать защиту от кодера-дурака.
И опять же, функция все равно будет протестирована косвенно в других тестах. Если этого не случилось, значит функцию можно смело удалить — она не нужна.
Если другой разработчик решит править функцию до правки ее теста, то это будет последняя функция, которую он поправит в этом проекте. В противном же случае он заметит отсутствие теста и, если таковой действительно необходим, напишет.
Во-вторых, я все же люблю включать мозг когда пишу код. Если я вижу, что вот эта тривиальная функция возвращает полное имя пользователя, то я не стану переписывать ее на возврат имени сервера.
В-третьих, эта функция в любом случае будет косвенно протестирована интеграционными тестами.
После рефакторинга код не может стать менее тривиальным, иначе это не refactoring, а refucktoring. В остальном:
Если же в будущем появится необходимость учитывать титул, второе имя, отчество или еще что-то, усложняющее функцию и добавляющее некую разветвленность в ее поведении — пишете тест и потом начинаете реализацию.
Я не горячусь ни в коем случае, дискуссия выходит крайне интересная. Просто объяснение одного и того же разным людям в рамках одной темы нарушает принцип DRY :)
В данном случае тест напоминает документацию в стиле «full_name — returns full name». Сомневаюсь, что хоть один разработчик напишет мне в скайп «Друг, я тут правлю твой код… А что за функция full_name?»
Если другой разработчик решит править функцию до правки ее теста, то это будет последняя функция, которую он поправит в этом проекте. В противном же случае он заметит отсутствие теста и, если таковой действительно необходим, напишет.
Возвращаясь опять же к Кенту, это личный уровень уверенности. Я знаю, что вероятность ошибки в конструкции "#{first_name} #{last_name}" крайне мала. Максимум, что там может пойти не так — опечатка, которую я сразу замечу, т.к. интерпретатор выдаст ошибку. Ну или завалится один из интеграционных тестов.
И почему по телевизору можно показывать сериалы про бандюков и домдва с предупреждением, мол до 16 нини, а в интернетах совсем ничего вообще нельзя (окромя восхваления царя-батюшки и господа Б-га, конечно)?
ЗЫ. Я понимаю, для чего создавался это закон, я говорю о его формулировке.
Но все же я склонен к тому, что тривиальность каждый определяет по себе и по своему «уровню уверенности».
Есть 2 ситуации, в которых правится код: Рефакторинг/оптимизация и добавление/изменение функционала. В первом случае правка тестов не нужна, т.к. требования к коду не меняются. Во втором правка кода непременно должна начаться с изменения тестов, т.к. это стандартный цикл тест — код — рефакторинг — тест — … итд.
Выше задавали вопрос о том, как понять, является ли функция тривиальной или нет. В дискуссии у меня родился ответ: если функцию при ее текущем функционале нельзя подвергнуть рефакторингу, она тривиальна.
Что за двойные стандарты? Если уж применяем TDD, то будьте добры начинать правку кода с тестов. А то получается, что делать допущения в моем случае — богомерзко, а в вашем — ничего страшного.
Омфг. Вот у меня есть тест, проверяющий правильность вывода списка пользователей. Он проверяет, что выводится имя и фамилия. До этого я «ручками» вставлял свойства «first_name» и «last_name». Со временем имена пользователей начали возникать то в одном, то в другом месте, и я, чтобы не нарушать принцип DRY, написал функцию-хелпер full_name. По факту эта функция проверяется во всех местах, где проверяется вывод пользователя. Если я напишу на нее отдельный тест, то это не отменит того, что она будет косвенно проверяться в остальных местах. Если я изменю эту функцию, то у меня завалится на 1 тест больше. Если я поменяю какой-то тест, то у меня станет на 1 противоречивый тест больше. Вот и вся разница.
Повторюсь в 100й раз, вы впадаете в крайности, считая программиста по-умолчанию идиотом, а тесты — панацеей. Приведенные вами примеры — эта абсолютная синтетика, имеющая с реальностью мало общего.
Это, опять же, не refActoring, а refUcktoring. Т.е. порча кода. Если какому-то разработчику вздумалось переименовать функцию или изменить ее функционал наобум, то ему хватит ума и удалить тест от старой функции и написать новый. Давайте для начала предположим, что не все разработчики идиоты, и не будем разрабатывать защиту от кодера-дурака.
И опять же, функция все равно будет протестирована косвенно в других тестах. Если этого не случилось, значит функцию можно смело удалить — она не нужна.
Во-вторых, я все же люблю включать мозг когда пишу код. Если я вижу, что вот эта тривиальная функция возвращает полное имя пользователя, то я не стану переписывать ее на возврат имени сервера.
В-третьих, эта функция в любом случае будет косвенно протестирована интеграционными тестами.
Возвращаясь опять же к Кенту, это личный уровень уверенности. Я знаю, что вероятность ошибки в конструкции "#{first_name} #{last_name}" крайне мала. Максимум, что там может пойти не так — опечатка, которую я сразу замечу, т.к. интерпретатор выдаст ошибку. Ну или завалится один из интеграционных тестов.