?

Log in

No account? Create an account
 
 
02 February 2017 @ 10:27 pm
Unit tests  
How do you convince a senior developer to write unit tests even when he thinks that his code is easy to understand?

I already tried:
1) Unit tests have test cases that help to understand the underlying business logic during code review.
2) Having automated test coverage makes code more maintainable, because tests allow quick experiments with changing underlying implementation.
3) Tests are needed anyway (manual or automatic), so why not immediately write auto-tests during development?

Update: LJ discussion.

Originally posted at: http://dennisgorelik.dreamwidth.org/123813.html
 
 
 
cikavac1968cikavac1968 on February 3rd, 2017 03:51 am (UTC)
В одной фирме мне не удалось убедить русского архитектора.
Dennis Gorelikdennisgorelik on February 3rd, 2017 05:50 am (UTC)
А где-нибудь удалось убедить?

Edited at 2017-02-03 05:50 am (UTC)
СБsab123 on February 3rd, 2017 06:32 pm (UTC)
Да, за примерно день убеждения мне удалось убедить одного человека :-) Его подход до убеждения был "но я же вручную протестировал".
Dennis Gorelikdennisgorelik on February 3rd, 2017 08:47 pm (UTC)
8 часов убеждения?
Какие аргументы оказались особенно убедительными?
Когда он начал писать тесты?

Edited at 2017-02-03 11:57 pm (UTC)
СБsab123 on February 4th, 2017 01:45 am (UTC)
Ну, может не прям так восемь, а примерно четыре. Писать начал сразу. Главный аргумент был пожалуй тот, что вот понадобится что-то поменять - а тут раз, и тесты готовы, запускаются сами. И если другому человеку окажется надо поменять, то тесты тоже уже готовы, не надо с нуля разбираться, как оно работает и придумывать как тестировать.
Dennis Gorelikdennisgorelik on February 4th, 2017 06:23 pm (UTC)
Thanks - I will repeat that argument. I think I used similar explanation before, but hopefully it would help to repeat it again.
Yaturkenzhensirhiv - a handheld spyyatur on February 3rd, 2017 05:00 am (UTC)
Unfortunately, to convince someone to do something your way, it is not enough to be right. The person needs to feel that it is more advantageous for them to follow your advice than not to follow it. This can take multiple forms: they may do it out of respect, or out of fear for their bonus/promotion/job, or because they they know you may nag them to death, or because they believe that your advise saves them time or money. If they think you're an idiot, and you don't have some kind of administrative resource to punish them for disobedience, your case is hopeless.

Now, to your arguments.

#1 is not believable, and is mostly false. For any non-trivial class, the tests must be extremely well written and named to actually help to understand the logic rather than obscure it and clutter the reader's mind with numerous corner cases.

#2 is only partially true. Tests help tremendously with fear-free refactoring, but they make code modification slower, because you must not only modify the code, but fix all the places where old tests are no longer relevant. Oftentimes you spend more time to fix quirks in the test rather than bugs in actual code.

#3 is the real reason. Tests are designed to facilitate steady progress and ensure that old bugs don't reappear without warning. This allows us to modify programs with less fear, thus keeping them lean and to the point, which is a good thing in the long run.
Dennis Gorelikdennisgorelik on February 3rd, 2017 05:48 am (UTC)
> don't have some kind of administrative resource to punish them for disobedience

As a business owner I have the administrative resource, but obviously I should use that resource wisely.

We are not talking about a silly coder here. He catches my mistakes and introduces original ideas too.

> tests must be extremely well written

Unit test gives at least one test case. That first test case helps a lot with understanding of the purpose of the underlying method.

> clutter the reader's mind with numerous corner cases

As soon as reader got enough test cases - he can stop reading unit test.
Besides, most of the time unit tests are short anyway.

In addition to that, in cases when we modify production code and simultaneously modify unit test - related changes are very visible in the diff. That helps readability too.

> they make code modification slower

That argument is usually getting important when we are trying to cover more and more test cases in our auto-tests.
Finding the right balance between test coverage and rigidity of codebase is a separate topic.
But having almost no autotests for production code - is usually wrong.


Edited at 2017-02-03 05:52 am (UTC)
Yaturkenzhensirhiv - a handheld spyyatur on February 3rd, 2017 06:09 am (UTC)
Silly coders are rarely a problem. They will usually just follow orders, albeit poorly. People that think they are smarter than you are a problem :)

> first test case helps a lot with understanding of the purpose of the underlying method.

Have you ever tried to understand logic of a unknown project/class by looking at unit tests instead of documentation? Did it work well? Obviously, I am talking about something more complicated than String.ToUpper().
Dennis Gorelikdennisgorelik on February 3rd, 2017 06:54 am (UTC)
> People that think they are smarter than you are a problem

True.

> understand logic of a unknown project/class

I know this project and know most of the classes.
But it still could be hard to understand code changes without corresponding use cases.

Obviously tests are not a full replacement for documentation. We have tasks that describe business goals. We have descriptive method and field names. We have code comments. We exchange emails.
But every documentation solution has gaps.
Test cases help to partially fill these gaps.

Edited at 2017-02-03 09:49 am (UTC)
Yaturkenzhensirhiv - a handheld spyyatur on February 3rd, 2017 12:40 pm (UTC)
Exactly. Tests may aid in filling the gaps and answer "what happens if" type of questions. They suck in documenting the foundation.
veremeenko_alex on February 3rd, 2017 09:03 am (UTC)
>1) Unit tests have test cases that help to understand the underlying business logic during code review.

Юнит тесты для этого не годятся, надо уровень повыше.

>2) Having automated test coverage makes code more maintainable, because tests allow quick experiments with changing underlying implementation.

маст хэв, но это интеграционные тесты и выше

>3) Tests are needed anyway (manual or automatic), so why not immediately write auto-tests during development?

Сами тесты - ок, но поддерживать их и чинить чужие - pain in ass
И есть момент с тем, что разработка новых фич позволяет выделится перед заказчиком, показать свой перфоманс и т.п. А тесты этому мешают.

Dennis Gorelikdennisgorelik on February 3rd, 2017 09:39 am (UTC)
> Юнит тесты для этого не годятся, надо уровень повыше.

All right, let's call them autotests.
He creates them only occasionally.

> это интеграционные тесты и выше

Functionality on the low level could be hard to reach with integration tests.
Or impractical to reach low level cases.
Both integration tests and unit tests are important.

> но поддерживать их и чинить чужие - pain in ass

Tests mostly play the role of a messenger:
In general it is hard to keep codebase in a working state.
veremeenko_alex on February 3rd, 2017 09:42 am (UTC)
Остается пункт - это не выгодно разработчику.
Dennis Gorelikdennisgorelik on February 3rd, 2017 09:47 am (UTC)
В каком смысле "не выгодно"?
Не интересно тратить время и усилия на написание тестов?
veremeenko_alex on February 3rd, 2017 09:55 am (UTC)
Не выгодно по результату. Если взять условный бодишоп.
Кто получит премию?
Кому будет что сказать при просьбе повышения зарплаты?
Кто будет на виду у заказчика?

Тот кто быстро разрабатывает новые фичи. Дали задание - оп уже готово, да с багами, да глючное, но уже есть что показать инвесторам.

А тот кто тратится на другое попадает в невыгодное положение.
Dennis Gorelikdennisgorelik on February 3rd, 2017 01:45 pm (UTC)
У нас инвесторов нет. Зато есть потребители.
Которым не нравится, если веб сайт не работает из-за багов.
А мне, соответственно, не нравится когда программисты выкатывают сломанный код в production.
veremeenko_alex on February 3rd, 2017 02:08 pm (UTC)
Тогда только quality gates со всеми плюшками как тесты и код ревью.

Код не проходит - давай доделывай.
Dennis Gorelikdennisgorelik on February 3rd, 2017 04:53 pm (UTC)
Так в том-то и дело, что без тестов код проходит.
А потом падает в production, когда девелопер спит.
Yaturkenzhensirhiv - a handheld spyyatur on February 3rd, 2017 06:13 pm (UTC)
Ну так будить гада пинками, и пусть чинит. :)
Dennis Gorelikdennisgorelik on February 3rd, 2017 08:28 pm (UTC)
Обычно, к тому времени как становится понятно, кто именно виноват в падении - уже примерно понятно как чинить.
Хотя в воспитательных целях может иметь смысл и разбудить.
СБsab123 on February 3rd, 2017 06:34 pm (UTC)
Ну так вод считать такие падения сугубо отрицательными факторами в оценке людей? Ты же сам оценку делаешь, вот и оценивай по своим критериям.
Dennis Gorelikdennisgorelik on February 3rd, 2017 08:46 pm (UTC)
Так я такие падения и считаю отрицательным фактором. Особенно если накосячивший программист отсутствует при падении.
Но делать-то с этим что?
Тем более, что основные проблемы от отсутствия автотестов не в прямых багах, а в осложнении работы других программистов, которые пытаются понять или изменить этот код.
Положим непосредственное падение maintenance programmer может избежать путём написания своих тестов. Но какие-то ключевые бизнес тест кейсы, которые были закодированы в изначальном коде - maintenance programmer может просто не знать, если они не были явно закодированы в виде автотестов.
СБsab123 on February 4th, 2017 05:14 pm (UTC)
Так ты же начальник (а то и хозяин конторы?). Дай нехорошую оценку, лиши премии и повышения зарплаты на будущий год, в конце концов понизь в должности.
Dennis Gorelikdennisgorelik on February 4th, 2017 06:37 pm (UTC)
> Так ты же начальник (а то и хозяин конторы?).

Ага - хозяин конторы.

> Дай нехорошую оценку,

Дал. ("We need test coverage, you agree to add tests but add tests only occasionally").
Но это же командным путём плохо решается.
Нужно же не просто формальное присутствие автотестов, а правильные автотесты - которые тестируют то, что нужно тестировать.

> понизь в должности

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

С этой точки зрения я сам пока что не заслужил "повышения в должности", потому что не сумел убедить всех разработчиков систематически писать тесты.
Unstable Bearunstablebear on February 3rd, 2017 12:30 pm (UTC)
I'd add one more not so obvious point, that writing tests could help with identifying smelly code, i.e. if your code is a spaghetti-type, then it's easy to feel when you start to write tests for this mess.
Dennis Gorelikdennisgorelik on February 3rd, 2017 04:05 pm (UTC)
> I'd add one more not so obvious point, that writing tests could help with identifying smelly code

That is true, but I am careful with using that argument, because auto-tests sometimes add undesired restrictions on production code too, which may actually increase complexity of production code.

The fact that we need to test anyway - means that production code architecture should accommodate testing requirement too. But count it as a benefit of autotests is a little bit too much.
occam_agaoccam_aga on February 3rd, 2017 08:06 pm (UTC)
Для меня юнит тесты существенно _ускоряют_ разработку. И это главный довод. Неужели кому то не лень тестить руками?
Dennis Gorelikdennisgorelik on February 3rd, 2017 08:34 pm (UTC)
Руками тестировать, конечно, тоже лень.
Особенно если способность к чтению кода позволяет хорошо отследить логику и отловить подавляющее большинство багов таким образом.
К сожалению, этого недостаточно для того, чтобы отловить всё и без тестов дурацкие ошибки просачиваются в production.
Что хуже, без тестов этот код страшно изменять другим разработчикам.
occam_agaoccam_aga on February 3rd, 2017 08:51 pm (UTC)
Т.е. кто-то не тестирует вообще никак ни руками ни юнит тестами?

Для меня разница в 50% отловленных багов и 99% несущественна. Багов, которые можно было отловить простым прогоном кода, руками ли, юнит тестами ли, быть не должно вообще.
Dennis Gorelikdennisgorelik on February 4th, 2017 12:18 am (UTC)
> Т.е. кто-то не тестирует вообще никак ни руками ни юнит тестами?

Ага.
Ну или есть какой-нибудь тест на самом верху. Но он далеко не весь код выполняет (из-за ветвлений).

Случаи разные бывают.
Вот есть, например, SQL код, который выбирает "top 1000" записей.
Из соображений производительности меняем это на "top 500" записей.
Если есть автотест - прогнать его просто и быстро.
А если нету - нужно потратить несколько минут, чтобы его написать. А лениво.
И это - простой случай.

> Багов, которые можно было отловить простым прогоном кода, руками ли, юнит тестами ли, быть не должно вообще.

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