Previous Entry Share Next Entry
2016-01

Про type coercion, юнит-тесты и перформанс

Неправильный код: if(cache.indexOf(query)) { fast_path }

Правильный код: if(cache.indexOf(query) != -1) { fast_path }

Ну и в итоге первый элемент кэша никогда не используется.

Вопрос: как это юнит-тестить? Работает-то оно одинаково, только с разной скоростью.

This entry was originally posted at http://wizzard.dreamwidth.org/395945.html. It has comment count unavailable comments. Please comment there using OpenID.

  • 1
ex_juan_gan October 22nd, 2014
Правильный - if (cache.contains(query)) {fast_path}

ex0_planet October 22nd, 2014
function contains(self, query) { return self.indexOf(query); }

Проблема-то не уходит, в лучшем случае на чужую голову перекладывается.

wizzard0 October 22nd, 2014
Ну почему, здесь хотя бы появляется место, в которое можно тест написать.

kodt_rsdn October 22nd, 2014

добавить в короткий и/или длинный код спецэффекты (отключаемые в релизе).
Да хоть в лог писать: промах кэша.


Кстати, для профилирования полезно, собрать статистику и подстроить кэш (размер его, хэш-функции разные и т.п.)


wizzard0 October 22nd, 2014
Вообще да, только профилирование != юнит-тесты :)

kodt_rsdn October 22nd, 2014

Воткнёшь код для ЮТ, заодно получишь средство для профилирования, ну или наоборот.


sab123 October 22nd, 2014
+1, писать лог работы кэша и проверять, что он правильный. Только не "отключаемые в релизе", а "включаемые флажком в объекте". И соответственно при тестировании включать этот флажок.

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

kodt_rsdn October 22nd, 2014
С флажками дело такое... особенно, в высоконагруженных приложениях.
Даже элементарное if(g_bDoTrace) LOG_MESSAGE(.....);
будучи дёрнуто 10млн раз в секунду, отожрёт десяток-другой ценных миллисекунд.
А если флажок поднят, тут вообще будет труба :)

ex0_planet October 22nd, 2014
статистику хитов собирать, не?

dmih October 22nd, 2014
Ну вообще когда я этой (глупостью) занимался, я юнит-тестил самописные коллекции всегда, каким-то рандомом, с seed-ом фиксированным. Т.е., если с этой точки зрения считать кеш коллекцией, то метод Cache.Contains() у меня безусловно был бы написан правильно.
Кеш тестировать безусловно стоит. Там миллион вещей на ошибиться - правила эспирации, корректное вытеснение и так далее, при которых либо инвалидные данные в приложении, либо ручной тормоз. Как же это не протестировать, зачем тогда тесты вообще нужны?

wizzard0 October 22nd, 2014
Ну да, выделить кеш в отдельную штуку и тестировать - это логично.

А так-то там он был однострочно припаян, в смысле, var cache = []; всего-то.

dmih October 22nd, 2014
Ну если у него нет никакой логики, то наверное простительно и такую ошибку продолбать.
Хотя в сущности это просто утечка, и если утечки покрыты ПРАВИЛЬНО, т.е. не в момент выхода из программы, а в точках транзакций, то ты её бы увидел. Но это тоже редко не делают (хотя это и довольно просто, если вообще анализатор утечек в тестовом ките есть, scope-ы расставляй та и ладно).

dmih October 22nd, 2014
Ну и строго говоря конечно, неявный boolean зло, и в языках, которые его имеют, и при этом не имеют warning-ов, JS всякий, PHP, Питон, вот это вся дрянь, им не надо пользоваться просто на уровне рефлексов.

wizzard0 October 22nd, 2014
ну вот да, я скорее именно про это.

dmih October 22nd, 2014
ну теоретически, должен быть наверное анализатор на эту тему?..

dmih October 22nd, 2014
Ну т.е. вот про bool, у меня это до того дошло, что в проекте на даже не знаю сколько строк (1gb.ru ;), часть которая php+mysql, bool строго int 0 и int 1. Неявного bool нет в принципе, даже на уровне a = (a==b), пишется (a==b)?1:0

dmih October 22nd, 2014
Посмотри тесты Хрома. Там вплоть до исходного HTML-я и попиксельного результата рендеринга. Конечно и кеш был бы покрыт со всех сторон и еще по 5 раз так же.

dmih October 22nd, 2014
(если конечно тесты не для самоуспокоения пишутся, как это обычно делают ;)

amarao_san October 22nd, 2014
А performance-тесты unit-тестами и не покрываются, и покрываться не должны. Если нужно просто "сработать что плохо" - выполнить цать раз с try/except по таймеру. Но надо понимать, что тестирующая машина может оказаться любой степени тормознутости и будет фейл.

rageous October 23rd, 2014
У нас часто встречается что-то подобное следующему:

Foo() {
  if (cached) { Stats.Increment("FastPath"); Fast(); }
  else { Stats.Increment("SlowPath"); Slow(); UpdateCache(); }
}

TestFooCaching() {
  Foo();
  AssertStatEquals(1, "SlowPath");
  AssertStatEquals(0, "FastPath");

  Foo();
  Foo();
  AssertStatEquals(1, "SlowPath");
  AssertStatEquals(2, "FastPath");
}


Понятно, что вместо Stats может выступать любое средство диагностики. В нашем случае, оно обычно остается и в продакшне: используется для реалтайм-диагностики, графиков, алертов, и т.п.

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

Edited at 2014-10-23 09:29 pm (UTC)

klonkaktusa October 24th, 2014
if(~cache.indexOf(query)) { fast_path }
Тильда перед indexOf как часть синтаксиса :)

wizzard0 October 24th, 2014
О, прекрасно!

  • 1
?

Log in

No account? Create an account