Re: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 10.10.13 17:53
Оценка: -9 :))) :)
Здравствуйте, Ikemefula, Вы писали:

I>Исходная посылка

спасибо, интересная статья.

I>Коментарий того самого eao197

я хз кто такой eao197, но он пишет очень глупые вещи %)
In Zen We Trust
Менеджер про хаскель в продакшне
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.10.13 16:04
Оценка: 30 (4) +1
Извиняюсь за хабр и жэжэ !

Исходная посылка

Коментарий того самого eao197

Еще коментарии
Re[2]: Менеджер про хаскель в продакшне
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 11.10.13 05:15
Оценка: 2 (2) +1 -1
Здравствуйте, DarkEld3r, Вы писали:

DE>

Из этого вытекает парадоксальный вывод: баги в программе на Хаскеле фиксить сложнее, чем в языках с динамической типизацией, потому что в языке с динамической типизацией очередное место, где вдруг внезапно вылез NoneType, поправил и ладушки, а на Хаскеле надо с алгоритмом разбираться да по повводу неясности ТЗ с другими людьми ругаться.

DE>Разве из этого следует, что в языках с динамической типизацией нет "сложных" багов (ошибка в тз)? Тогда проще пофиксить разве что "средний баг", а в целом наоборот хуже ведь? А преподносится как достоинство, ну или мне так показалось.

Языки с продвинутой статтипизацией заставляют больше думать. В иных языках можно вставлять заплатки по месту и так из заплаток все и строить, типа:
def isPrime(x)
  x==2 || x % 2 == 1 
end

тесты:
isPrime(2) == true
isPrime(3) == true
isPrime(7) == true
isPrime(10) == false
isPrime(11) == true
пока неплохо

isPrime(9) == false 
упс, тест не прошел, но у нас же TDD, в миг все поправим:

def isPrime(x)
  x==2 || (x % 2 == 1 && x != 9) 
end

Ура!

С хорошей статтипизацией подобный подход не работает, приходится реально думать о проблеме, а не тупо делать подкладки под тесты.
Re: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 26.10.13 18:44
Оценка: +2
Здравствуйте, Ikemefula, Вы писали:

I>Извиняюсь за хабр и жэжэ !


I>Исходная посылка


Статья совершенно ни о чём.

I>Коментарий того самого eao197


I>Еще коментарии


Женя (eao197) всё, в сущности, правильно написал. Самого главного из исходной статьи не понятно: что же именно переписывали и в каком контексте обитает разработка. Можно строить предположения, но они останутся предположениями.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[5]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 26.10.13 22:03
Оценка: -2
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Здравствуйте, Abyx, Вы писали:


A>>>>я хз кто такой eao197, но он пишет очень глупые вещи %)

A>>>А в чем глупость?
A>>зачем переписывать код на хаскел — глупый вопрос, ответ очевиден — программистам надо кушать и развлекаться, иначе они разбегутся.
A>>ну и еще есть мечта что "код станет лучше".

ГВ>Решение о переписывании в конечном итоге принимает менеджмент, поскольку он отвечает за использование средств компании. И вопрос "зачем" eao197 ставит, прежде всего, с позиций руководителя.


средства компании тратятся в любом случае, ежемесячно, на зарплату программистам.
в не зависимости от того чем они занимаются.

когда в плане пусто, программистов надо чем-то занять, и перепиливание кода — один из лучших вариантов, IMO.

ГВ>

Но зачем, почему? Это не праздные вопросы для ПМа и руководства.


так что по-моему это вопросы из серии "зачем в армии строем ходят"

ГВ>Насколько я понял, предыстория описана здесь: Открытие облака для новых клиентов. И там описаны вполне рациональные причины если и не перехода на Haskell, то уж по крайней мере — отказа от Python.


A>>автор верит в 146% процентное покрытие программы автоматическими тестами, и что юнит тесты могут выловить *все* ошибки.


ГВ>eao197 прямо говорит, что тестирование — единственный способ бороться с ошибками "забывчивости" в динамических языках.


ГВ>

Вообще, когда якобы ПМ начинает говорить, что в выпущенном в продакшен Питоновском коде вылазят ошибки типизации или отсутствие обработки каких-то ситуаций, то этот ПМ сам расписывается в собственной неспособности управлять разработкой. Да, в языках с динамической типизацией есть такая особенность. ПМ этого не знал? Не знал того, что единственным способом борьбы с этим явлением является тестирование [...]


ГВ>*Все* ошибки не выловят ни тесты, ни наилучшие языки.


в статье написано

Тесты, которые «покрывают весь код», к сожалению, совсем не покрывают «все возможные типы входных данных» (которые, внезапно, динамические) и совсем не спасают от ошибок типизации.


я из этого понял что у них уже были автоматические тесты, и были баги которые тесты не отлавливали.
а вот eao197 то ли этот абзац не читал, или говорит что "они не умеют тестировать, вот если бы там был Я, багов бы не было вообще."
In Zen We Trust
Re[6]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 27.10.13 00:18
Оценка: +2
Здравствуйте, Abyx, Вы писали:

ГВ>>Решение о переписывании в конечном итоге принимает менеджмент, поскольку он отвечает за использование средств компании. И вопрос "зачем" eao197 ставит, прежде всего, с позиций руководителя.


A>средства компании тратятся в любом случае, ежемесячно, на зарплату программистам.

A>в не зависимости от того чем они занимаются.
A>когда в плане пусто, программистов надо чем-то занять, и перепиливание кода — один из лучших вариантов, IMO.

На каком основании ты решил, что "в плане пусто"? Цитату можешь привести?

ГВ>>

Но зачем, почему? Это не праздные вопросы для ПМа и руководства.

A>так что по-моему это вопросы из серии "зачем в армии строем ходят"

Это вопросы, которые обязан задавать ПМ. Вне зависимости от того, какие у кого коннотации возникают по этому поводу.

ГВ>>Насколько я понял, предыстория описана здесь: Открытие облака для новых клиентов. И там описаны вполне рациональные причины если и не перехода на Haskell, то уж по крайней мере — отказа от Python.

A>>>автор верит в 146% процентное покрытие программы автоматическими тестами, и что юнит тесты могут выловить *все* ошибки.

ГВ>>eao197 прямо говорит, что тестирование — единственный способ бороться с ошибками "забывчивости" в динамических языках.


ГВ>>

Вообще, когда якобы ПМ начинает говорить, что в выпущенном в продакшен Питоновском коде вылазят ошибки типизации или отсутствие обработки каких-то ситуаций, то этот ПМ сам расписывается в собственной неспособности управлять разработкой. Да, в языках с динамической типизацией есть такая особенность. ПМ этого не знал? Не знал того, что единственным способом борьбы с этим явлением является тестирование [...]


ГВ>>*Все* ошибки не выловят ни тесты, ни наилучшие языки.


A>в статье написано

A>

A>Тесты, которые «покрывают весь код», к сожалению, совсем не покрывают «все возможные типы входных данных» (которые, внезапно, динамические) и совсем не спасают от ошибок типизации.


A>я из этого понял что у них уже были автоматические тесты, и были баги которые тесты не отлавливали.


Из этого следует, что тестовое покрытие было недостаточным. Что вполне естественно — если язык допускает "Not implemented"-методы, то тесты должны покрывать *все* случаи, где такие методы могут быть задействованы. Очевидно, что этого сделано не было.

Пребанальнейший вывод, не правда ли?

A>а вот eao197 то ли этот абзац не читал, или говорит что "они не умеют тестировать, вот если бы там был Я, багов бы не было вообще."


Оспаривать то, что тебе показалось, я не собираюсь. Разбирайся со своими тараканами сам. Могу только посоветовать перечитать то, что написано у Охотникова (eao197), там всё вполне однозначно изложено.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[2]: Менеджер про хаскель в продакшне
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.10.13 17:57
Оценка: 2 (1)
Здравствуйте, Abyx, Вы писали:

I>>Исходная посылка

A>спасибо, интересная статья.

I>>Коментарий того самого eao197

A>я хз кто такой eao197, но он пишет очень глупые вещи %)

Вот
http://rsdn.ru/stat/top/philosophy
Re[3]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 10.10.13 19:15
Оценка: :)
Здравствуйте, Alex912, Вы писали:

A>>я хз кто такой eao197, но он пишет очень глупые вещи %)

A>А в чем глупость?

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

программы питоне не медленные, т.к. обычно это "скрипты для управления быстрыми библиотеками на Си".

автор верит в 146% процентное покрытие программы автоматическими тестами, и что юнит тесты могут выловить *все* ошибки.
In Zen We Trust
Re[4]: Менеджер про хаскель в продакшне
От: Plague Россия 177230800
Дата: 11.10.13 10:47
Оценка: +1
Здравствуйте, Abyx, Вы писали:

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

Вы путаете вопросы "Зачем" и "Почему", т.е. цель переписывания на Хаскелл неясна, а вот причины понятны...

A>ну и еще есть мечта что "код станет лучше".

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

A>программы питоне не медленные, т.к. обычно это "скрипты для управления быстрыми библиотеками на Си".

я так понимаю, автор имел ввиду, что питон управляет внешними библиотеками/утилитами на которых и лежит основная нагрузка, поэтому оптимизировать там, где не тормозит — не стоит

A>автор верит в 146% процентное покрытие программы автоматическими тестами, и что юнит тесты могут выловить *все* ошибки.

Юнит тесты не решают архитектурных "изысков" и не очевидных решений, зато могут отловить опечатки и ошибки "копи-паста", особенно в динамических языках
Re[2]: Менеджер про хаскель в продакшне
От: AndrewVK Россия http://blogs.rsdn.org/avk
Дата: 18.10.13 20:23
Оценка: +1
Здравствуйте, Abyx, Вы писали:

A>я хз кто такой eao197, но он пишет очень глупые вещи %)


Глупость там в основном в абзаце про растаманов программистов из глубинки. Остальное более менее по делу.
... << RSDN@Home 1.2.0 alpha 5 rev. 100 on Windows 8 6.2.9200.0>>
AVK Blog
Re[10]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 27.10.13 12:34
Оценка: -1
Здравствуйте, Abyx, Вы писали:

A>>>расскажи пожалуйста какие тесты ты напишешь чтобы покрыть все случаи вызова call_foo с любыми obj

ГВ>>Здесь надо тестировать не саму call_foo, а соблюдение контракта её вызова.

A>а какой у нее контракт вызова? аргумент не None?


Я так понимаю, что это объект, у которого имеется метод foo. Не None, да.

A>значит для каждого места вызова call_foo надо внедрить mock_call_foo которая проверит аргумент?


Не знаю. Соблюдение контракта может отслеживаться и с более высоких уровней вызова. Зависит от программы.

A>но внезапно оказывается что у 99% функций такой контракт, и их все надо проверять?


Вполне может оказаться и так. Равно как может и оказаться, что программу придётся перепроектировать для "тестопригодности".

A>представь что у тебя в коде параметрами функций могут быть только указатели,

A>т.е. int* add(int* a, int* b) вместо int add(int a, int b)
A>и ты серьезно говоришь что "тесты должны покрывать *все* случаи, где такие методы функции могут быть задействованы"?
A>т.е. *каждый* вызов *каждой* функции?

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

ГВ>>Откуда берётся входной obj?

A>в каждом из 100500 вызовов call_foo — по разному.
A>аргумент другой функции, поле класса, элемент коллекции — откуда угодно.

А откуда берутся аргументы другой функции, поле класса и элемент коллекции? Самозарождаются?

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

В защиту тезиса б). Насколько я понимаю, под загадочной формулировкой "динамические типы входных данных" имеются в виду такие, которые при преобразовании к некоему ожидавшемуся типу давали None. ИМХО, такую ситуацию, в общем, легко предсказать и не так уж и сложно протестировать. Возможно, придётся поломать голову кое-где, но задача-то уже ясна.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[11]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 27.10.13 13:08
Оценка: -1
Здравствуйте, Геннадий Васильев, Вы писали:

A>>а какой у нее контракт вызова? аргумент не None?

A>>но внезапно оказывается что у 99% функций такой контракт, и их все надо проверять?

ГВ>Вполне может оказаться и так. Равно как может и оказаться, что программу придётся перепроектировать для "тестопригодности".

что значит "Вполне может оказаться и так" и "перепроектировать"? это свойство языка

ГВ>>>Откуда берётся входной obj?

A>>в каждом из 100500 вызовов call_foo — по разному.
A>>аргумент другой функции, поле класса, элемент коллекции — откуда угодно.

ГВ>А откуда берутся аргументы другой функции, поле класса и элемент коллекции? Самозарождаются?

сорока на хвосте приносит. third-party код выдает.

ГВ>Насколько я понимаю, под загадочной формулировкой "динамические типы входных данных" имеются в виду такие, которые при преобразовании к некоему ожидавшемуся типу давали None.

под этой формулировкой, в контексте языка программирования с динамической типизацией (dynamic typing), понимаются динамические типы (dynamically-typed) входных данных.

ГВ>Я одного не пойму: что ты мне хочешь доказать?

то что ты не разбираешься в ЯП с динамической типизацией, не разбираешься в тестировании кода таких ЯП, но при этом за компанию с eao197 пытаешься критиковать программистов на этих языках.

я тебе уже говорил, если не знаешь Python, возьми свой любимый кусок кода на Си или С++, замени все типы на указатели, и попробуй написать тесты которые покроют все разыменования указателей — тогда может поймешь почему в Python есть проблема с NoneType у аргументов.
или возьми C# и замени все типы на Nullable<T>.
In Zen We Trust
Re[12]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 27.10.13 13:43
Оценка: +1
Здравствуйте, Abyx, Вы писали:

ГВ>>>>Откуда берётся входной obj?

A>>>в каждом из 100500 вызовов call_foo — по разному.
A>>>аргумент другой функции, поле класса, элемент коллекции — откуда угодно.

ГВ>>А откуда берутся аргументы другой функции, поле класса и элемент коллекции? Самозарождаются?

A>сорока на хвосте приносит. third-party код выдает.

Отлично. А что же с ними происходит дальше? Мы эти данные принимаем от third-party и исполненные уверенности, что они никогда-никогда не ошибаются? Допустим. Но вменяемые люди так поступают ровно до первой ситуации, когда thrid-party выдаёт нечто недопустимое. После этого всё, поступившее оттуда начинают проверять.

ГВ>>Насколько я понимаю, под загадочной формулировкой "динамические типы входных данных" имеются в виду такие, которые при преобразовании к некоему ожидавшемуся типу давали None.

A>под этой формулировкой, в контексте языка программирования с динамической типизацией (dynamic typing), понимаются динамические типы (dynamically-typed) входных данных.

ГВ>>Я одного не пойму: что ты мне хочешь доказать?

A>то что ты не разбираешься в ЯП с динамической типизацией, не разбираешься в тестировании кода таких ЯП, но при этом за компанию с eao197 пытаешься критиковать программистов на этих языках.

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

A>я тебе уже говорил, если не знаешь Python, возьми свой любимый кусок кода на Си или С++, замени все типы на указатели, и попробуй написать тесты которые покроют все разыменования указателей — тогда может поймешь почему в Python есть проблема с NoneType у аргументов.


Что-то я не понимаю, я очень давно не испытываю проблем с указателями на C++... Так что, лучше обойдёмся без аналогий, ты уж прямо расскажи, что за проблема у Python с NoneType.

A>или возьми C# и замени все типы на Nullable<T>.


А... Начинаю понимать. Любые данные в Python могут быть NoneType? И что теперь? А в LISP любой параметр может быть NIL, но программы же как-то работают, притом работают очень неплохо.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[16]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 28.10.13 03:28
Оценка: +1
Здравствуйте, Abyx, Вы писали:

A>нет. ты до сих пор не понял что такое "динамическая типизация" и о каких "входных данных" речь.


A>если тебе близок C#, то код моделирующий проблему выглядит так


A>
A>void f(dynamic x)
A>{
A>    x.m();
A>}
A>


A>под "входными данными" понимаются любые входные данные функций (unit'ов) — параметры функций, глобальные переменные — все что unit (класс/функция) получает на вход.


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

A>в этом коде "входные данные" это "x".


В этом коде "x" — формальный параметр.

A>еще раз, речь не о данных от юзера, или других данных на входе программы.

A>речь о данных на входе каждого unit'a кода.

A>и вот автор статьи говорит:

A>"Тесты, которые «покрывают весь код»" — т.е. тесты покрывающие код f (и вообще любого другого юнита кода),
A>"не покрывают «все возможные типы входных данных»" — потому что аргументом f может оказаться что угодно,
A>потому что в ЯП динамические типы данных.

Стоп. С этого места я попрошу тебя перестать гнать пургу. "Что угодно" никогда нигде не оказывается, вне зависимости от того, какая типизация используется в данном языке программирования. И вменяемые люди никогда не полагаются на "что угодно". Вот смотри, на вскидку взятый кусок кода из питоновской библиотеки. Этот код ориентирован на враждебный внешний мир, подсовывающий неизвестно, что:

def start_new_thread(function, args, kwargs={}):
    ...
    if type(args) != type(tuple()):
        raise TypeError("2nd arg must be a tuple")
    if type(kwargs) != type(dict()):
        raise TypeError("3rd arg must be a dict")
    ...


То есть, формально говоря, на вход start_new_thread можно передать что угодно. Но она отсечёт это "что угодно" с исключениями. Ничего неожиданного. Точно такой же подход можно применить и в программе пользователя. Можно проверить содержимое атрибутов фактического параметра, можно сократить эти проверки до проверки типа и т.п. Короче говоря, всё как обычно. И тестирование таких функцией, в общем, ничем не отличается от тестирования программ на C, использующих указатели: тестами мы доказываем работоспособность программы и в том числе, её "умение" определять недопустимые комбинации входных данных.

A>я хз как еще это объяснить %)

A>все типы аргументов, членов классов, вообще все типы — это "dynamic", и юнит-тесты никак не могут отловить ошибки типизации.

Могут. И должны. Потому что если к типу объекта никаких требований не предъявляется, то мы им и не пользуемся и он находится за рамками нашей программы. А если пользуемся (методы там вызываем, атрибуты дёргаем), то нам нужно проверять его характеристики. То есть проверять имена типов, наличие нужных атрибутов у этих типов и т.п. Для статически типизированного языка это делает компилятор, для динамически типизированного — руки программиста. И если мы этого не делаем, то виноват не язык, а... Я уже писал, кто виноват.

То же самое и с тестами. Должны быть как тесты, имитирующие некорректные входные данные, так и тесты, которые проверяют структуру выходных данных.

A>интеграционные тесты для N юнитов не могут отловить ошибки типизации, если система из этих юнитов сводится к f(dynamic x).


А вот тут я снова чего-то не понимаю. Разве можно создать объект типа dynamic (за исключением Object или его аналога, который, само собой, почти никем не может использоваться)? Именно создать объект, а не объявить формальный параметр? Если нельзя, то система unit-тестов (и интеграционных) всё равно строится на каких-то вполне определённых типах и снова возникает противоречие: "тип любой, но с определёнными характеристиками".

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


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

A>только такая система будет слишком большой и потому нетестируемой.


Да нет, такая система будет обыкновенной.

A>


ГВ>>
ГВ>>SomeType typedData = castToSomeType(data);
ГВ>>

A>SomeType это *статический* тип. в языках с динамической типизацией нету статических типов. *вообще нету*. и кастов-к-статическому-типу нету, потому что (внезапно) нету статических типов.

За-ши-бись! То есть в Python конструкция type(obj) есть, а типов — нет. Ж..а есть, а слова нет. Ну, где у вас там ещё 0==1?

A>в языках с динамической типизацией у объектов нету статического набора методов. и нельзя сказать "у SomeType всегда есть метод foo".


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

... если язык допускает "Not implemented"-методы, то тесты должны покрывать *все* случаи, где такие методы могут быть задействованы.


По сути не имеет никакого значения, "Not Implemented"-метод или "объект, у которого отсутствует искомый метод".

A>объект может иметь тип SomeType, но может ему не добавили метод foo, или у него удалили метод foo.

A>
A>class SomeType: # создали тип
A>    pass

A>x = SomeType() # создали объект
A>x.foo = some_foo # добавили метод
A>del x.foo # удалили метод
A>


Кстати, а разве в Python можно аналогично удалять методы класса (а не объекта)?

class SomeType: # создали тип
    def foo(self):
        print("SomeType.foo")

x = SomeType() # создали объект
del x.foo # ???
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[18]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 28.10.13 14:36
Оценка: +1
Здравствуйте, Abyx, Вы писали:

A>это неудачный пример. в start_new_thread эти проверки только для того чтобы получить красивое сообщение о нарушении контракта, потому что в документации сказано "args must be a tuple".

A>заметь, что там нет проверки типа параметра "function"

Есть, хотя и неявная:

    try:
        function(*args, **kwargs)
    except SystemExit:
        pass
    except:
        import traceback
        traceback.print_exc()


Не только проверка, но ещё и печать стека.

A>в реальном коде никто не проверяет типы аргументов. (если для этого нет каких-то особых причин)


A>т.е. никто не пишет код типа

A>
A>def f(x):
A>    if not hasattr(x, 'm'): raise AttributeError('...')
A>    x.m()
A>

A>потому что эта проверка дублирует работу виртуальной машины Pyhthon'а

Ничего подобного. Эта проверка выполняется до обращения к атрибуту, а не в момент оного, поэтому функционально она не дублирует проверки Python VM.

ГВ>>Точно такой же подход можно применить и в программе пользователя. Можно проверить содержимое атрибутов фактического параметра, можно сократить эти проверки до проверки типа и т.п. Короче говоря, всё как обычно. И тестирование таких функцией, в общем, ничем не отличается от тестирования программ на C, использующих указатели: тестами мы доказываем работоспособность программы и в том числе, её "умение" определять недопустимые комбинации входных данных.


A>этот подход не дает ничего. Python сам делает все проверки типов и выбрасывает исключения, только немного с другим текстом, типа "NoneType has no attribute m".


Да ты что? Правда? То есть ранняя диагностика некорректных данных не даёт ничего? Блин, а мужики-то и не знают.

Перефразируя: этот подход ничего не даёт для C, потому что ОС сама предотвратит обращение по заведомо некорректным адресам, только немного с другим текстом, типа "General Protection Fault".

A>написание проверок типов руками позволяет добиться только user-friendly сообщений об ошибках, не более того.


Это уже очень сильно не "ничего". Как минимум, мы выигрываем время на поиске причин ошибок. И плюс к тому, можем быстрее и проще написать тесты.

ГВ>>То же самое и с тестами. Должны быть как тесты, имитирующие некорректные входные данные, так и тесты, которые проверяют структуру выходных данных.


A>тесты *чего*?

A>юнита? — они не помогают.

Откуда я знаю, тесты чего именно? Нужно смотреть по программе. Обычный подход — выделяют некие модули, фиксируют их контракты и тестируют соответствие этому контракту. Какие именно модули нужно выделять — вопрос сугубо индивидуальный, наивные советы в духе "класс = unit" или "функция = unit" тут помогают слабо.

A>всей программы размером в 100500 LOC? — такие тесты всегда не покрывают все случаи. их вообще непонятно как писать %)


Значит, нужно в этом вопросе разобраться и синтезировать соответствующее решение. Я не говорю, что это легко, но и как правило, не невозможно.

Или признать одно из двух: либо Python (и другие языки с динамической типизацией) принципиально УГ; либо у кого-то "руки не из того места растут". Третьего не дано.

A>>>интеграционные тесты для N юнитов не могут отловить ошибки типизации, если система из этих юнитов сводится к f(dynamic x).


ГВ>>А вот тут я снова чего-то не понимаю. Разве можно создать объект типа dynamic


A>
A>dynamic x = new System.Dynamic.ExpandoObject();
A>x.y = 1;
A>return x.y;
A>


Ясно, был не прав, хотя в общем — тот же Object, только в профиль. Однако, принципиально это снова ничего не меняет. Потому что дальше к dynamic-объекту всё равно предъявляются вполне определённые требования, например, наличия тех или иных атрибутов. Следовательно, технически, объект может быть dynamic, но функционально всё равно есть некий контракт, которому он должен удовлетворять.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[29]: Менеджер про хаскель в продакшне
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 31.10.13 12:32
Оценка: :)
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Остаётся признать принципиальную нетестопригодность программ на JS и как следствие, принципиальную непригодность JS для сколь-нибудь серьёзной работы.


Так и есть!
Re[2]: Менеджер про хаскель в продакшне
От: Alex912  
Дата: 10.10.13 18:49
Оценка:
Здравствуйте, Abyx, Вы писали:

A>я хз кто такой eao197, но он пишет очень глупые вещи %)


А в чем глупость?
Re: Менеджер про хаскель в продакшне
От: DarkEld3r  
Дата: 10.10.13 22:15
Оценка:
Как-то не понял этот аргумент совсем:

По опыту разборов найденных ошибок я могу сказать, что большая часть ошибок, с которыми мы сталкивались — это либо ошибка в ТЗ (то есть ошибка вашего покорного слуги), либо неправильно понятое ТЗ программистами. Но не локальная ошибка или забывчивость.

Из этого вытекает парадоксальный вывод: баги в программе на Хаскеле фиксить сложнее, чем в языках с динамической типизацией, потому что в языке с динамической типизацией очередное место, где вдруг внезапно вылез NoneType, поправил и ладушки, а на Хаскеле надо с алгоритмом разбираться да по повводу неясности ТЗ с другими людьми ругаться.

Разве из этого следует, что в языках с динамической типизацией нет "сложных" багов (ошибка в тз)? Тогда проще пофиксить разве что "средний баг", а в целом наоборот хуже ведь? А преподносится как достоинство, ну или мне так показалось.
Re[2]: Менеджер про хаскель в продакшне
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 11.10.13 05:01
Оценка:
Здравствуйте, DarkEld3r, Вы писали:

DE>Как-то не понял этот аргумент совсем:

DE>

DE>По опыту разборов найденных ошибок я могу сказать, что большая часть ошибок, с которыми мы сталкивались — это либо ошибка в ТЗ (то есть ошибка вашего покорного слуги), либо неправильно понятое ТЗ программистами. Но не локальная ошибка или забывчивость.

DE>Из этого вытекает парадоксальный вывод: баги в программе на Хаскеле фиксить сложнее, чем в языках с динамической типизацией, потому что в языке с динамической типизацией очередное место, где вдруг внезапно вылез NoneType, поправил и ладушки, а на Хаскеле надо с алгоритмом разбираться да по повводу неясности ТЗ с другими людьми ругаться.

DE>Разве из этого следует, что в языках с динамической типизацией нет "сложных" багов (ошибка в тз)? Тогда проще пофиксить разве что "средний баг", а в целом наоборот хуже ведь? А преподносится как достоинство, ну или мне так показалось.

Не ясно, что он имел ввиду. Может взял сравнил чисто среднее время на фикс в Питоне и Хаскеле, ежу понятно, что в Хаскеле это будет больше, если меньше багов из за забывчивости. А может другая идея — костылями обкладывать в Хаскеле дороже.
Re[3]: Менеджер про хаскель в продакшне
От: monax  
Дата: 11.10.13 09:30
Оценка:
Здравствуйте, D. Mon, Вы писали:

DM>Языки с продвинутой статтипизацией заставляют больше думать. В иных языках можно вставлять заплатки по месту и так из заплаток все и строить, типа:

DM>
DM>def isPrime(x)
DM>  x==2 || x % 2 == 1 
DM>end

DM>тесты:
DM>isPrime(2) == true
DM>isPrime(3) == true
DM>isPrime(7) == true
DM>isPrime(10) == false
DM>isPrime(11) == true
DM>пока неплохо

DM>isPrime(9) == false 
DM>упс, тест не прошел, но у нас же TDD, в миг все поправим:

DM>def isPrime(x)
DM>  x==2 || (x % 2 == 1 && x != 9) 
DM>end

DM>Ура!
DM>

DM>С хорошей статтипизацией подобный подход не работает, приходится реально думать о проблеме, а не тупо делать подкладки под тесты.

Может оно и так, но вот глядя на твой пример, я не могу понять, как тебе строгая типизация тут поможет. Ты не добавил новых типов данных, ты только увеличил количество операндов в логическом выражении. Как тут хорошая статическая типизация спасёт? И давай заодно определимся с терминами, чтобы не путать друг друга: в каком языке статическая типизация хорошая, а где плохая?
Re[4]: Менеджер про хаскель в продакшне
От: D. Mon Великобритания http://thedeemon.livejournal.com
Дата: 11.10.13 10:20
Оценка:
Здравствуйте, monax, Вы писали:

M>Может оно и так, но вот глядя на твой пример, я не могу понять, как тебе строгая типизация тут поможет.


Это была лишь утрированная иллюстрация самой идеи, подхода, не конкретный пример для обсуждения.

M> Ты не добавил новых типов данных, ты только увеличил количество операндов в логическом выражении. Как тут хорошая статическая типизация спасёт?


Если угодно, вот тут есть примеры, где типы позволяют отловить в том числе ошибки в арифметике:
http://thedeemon.livejournal.com/59724.html
http://thedeemon.livejournal.com/41035.html
http://thedeemon.livejournal.com/41545.html

M> И давай заодно определимся с терминами, чтобы не путать друг друга: в каком языке статическая типизация хорошая, а где плохая?


Например так: в Си и Java плохая, в Хаскеле и Окамле близка к хорошей, в Идрисе, Агде и ATS, пожалуй, хорошая.
Re: Менеджер про хаскель в продакшне
От: artem.komisarenko Украина  
Дата: 11.10.13 23:33
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Коментарий того самого eao197


Всё правильно сказал
Updated: Нет, не всё
Re: Менеджер про хаскель в продакшне
От: neFormal Россия  
Дата: 26.10.13 19:19
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Извиняюсь за хабр и жэжэ !

I>Исходная посылка
I>Коментарий того самого eao197
I>Еще коментарии

тема проблем не раскрыта. требуются слайды.
...coding for chaos...
Re[4]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 26.10.13 19:50
Оценка:
Здравствуйте, Abyx, Вы писали:

A>>>я хз кто такой eao197, но он пишет очень глупые вещи %)

A>>А в чем глупость?
A>зачем переписывать код на хаскел — глупый вопрос, ответ очевиден — программистам надо кушать и развлекаться, иначе они разбегутся.
A>ну и еще есть мечта что "код станет лучше".

Решение о переписывании в конечном итоге принимает менеджмент, поскольку он отвечает за использование средств компании. И вопрос "зачем" eao197 ставит, прежде всего, с позиций руководителя.

Но зачем, почему? Это не праздные вопросы для ПМа и руководства.


Насколько я понял, предыстория описана здесь: Открытие облака для новых клиентов. И там описаны вполне рациональные причины если и не перехода на Haskell, то уж по крайней мере — отказа от Python.

A>программы питоне не медленные, т.к. обычно это "скрипты для управления быстрыми библиотеками на Си".


A>автор верит в 146% процентное покрытие программы автоматическими тестами, и что юнит тесты могут выловить *все* ошибки.


eao197 прямо говорит, что тестирование — единственный способ бороться с ошибками "забывчивости" в динамических языках.

Вообще, когда якобы ПМ начинает говорить, что в выпущенном в продакшен Питоновском коде вылазят ошибки типизации или отсутствие обработки каких-то ситуаций, то этот ПМ сам расписывается в собственной неспособности управлять разработкой. Да, в языках с динамической типизацией есть такая особенность. ПМ этого не знал? Не знал того, что единственным способом борьбы с этим явлением является тестирование [...]


*Все* ошибки не выловят ни тесты, ни наилучшие языки.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[5]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 26.10.13 19:57
Оценка:
ГВ>Насколько я понял, предыстория описана здесь: Открытие облака для новых клиентов. И там описаны вполне рациональные причины если и не перехода на Haskell, то уж по крайней мере — отказа от Python.

Забавно, но оказывается, что это событие "обсуждалось" и на RSDN: http://www.rsdn.ru/forum/flame.comp/4616391.1
Автор: graninas
Дата: 14.02.12
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[7]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 27.10.13 09:45
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>>>*Все* ошибки не выловят ни тесты, ни наилучшие языки.


A>>в статье написано

A>>

A>>Тесты, которые «покрывают весь код», к сожалению, совсем не покрывают «все возможные типы входных данных» (которые, внезапно, динамические) и совсем не спасают от ошибок типизации.


A>>я из этого понял что у них уже были автоматические тесты, и были баги которые тесты не отлавливали.


ГВ>Из этого следует, что тестовое покрытие было недостаточным. Что вполне естественно — если язык допускает "Not implemented"-методы, то тесты должны покрывать *все* случаи, где такие методы могут быть задействованы. Очевидно, что этого сделано не было.


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

кстати с статье говорится не про "Not implemented"-методы, а про "Null Pointer Dereference" (Object of type 'NoneType' has no method), но это не важно.

давай может возьмем конкретный пример?

def call_foo(obj):
    obj.foo()

вызовов call_foo много и они равномерно размазаны по всему коду

расскажи пожалуйста какие тесты ты напишешь чтобы покрыть все случаи вызова call_foo с любыми obj
In Zen We Trust
Re[8]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 27.10.13 10:52
Оценка:
Здравствуйте, Abyx, Вы писали:

ГВ>>Из этого следует, что тестовое покрытие было недостаточным. Что вполне естественно — если язык допускает "Not implemented"-методы, то тесты должны покрывать *все* случаи, где такие методы могут быть задействованы. Очевидно, что этого сделано не было.


A>ты сам себе противоречишь.

A>сначала ты говоришь "*Все* ошибки не выловят ни тесты, ни наилучшие языки.", а потом "тестовое покрытие было недостаточным, тесты должны покрывать *все* случаи".

Ты бы ещё буквы в словах переставил. Я написал: "*все* случаи, где такие методы могут быть задействованы". Как ты понимаешь, это не "все" ошибки вообще.

A>кстати с статье говорится не про "Not implemented"-методы, а про "Null Pointer Dereference" (Object of type 'NoneType' has no method), но это не важно.


И правда. Но принципиально это ничего не меняет.

A>давай может возьмем конкретный пример?


A>
A>def call_foo(obj):
A>    obj.foo()
A>

A>вызовов call_foo много и они равномерно размазаны по всему коду

A>расскажи пожалуйста какие тесты ты напишешь чтобы покрыть все случаи вызова call_foo с любыми obj


Здесь надо тестировать не саму call_foo, а соблюдение контракта её вызова. Откуда берётся входной obj?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[9]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 27.10.13 11:46
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

A>>давай может возьмем конкретный пример?


A>>
A>>def call_foo(obj):
A>>    obj.foo()
A>>

A>>вызовов call_foo много и они равномерно размазаны по всему коду

A>>расскажи пожалуйста какие тесты ты напишешь чтобы покрыть все случаи вызова call_foo с любыми obj


ГВ>Здесь надо тестировать не саму call_foo, а соблюдение контракта её вызова.


а какой у нее контракт вызова? аргумент не None?
значит для каждого места вызова call_foo надо внедрить mock_call_foo которая проверит аргумент?

но внезапно оказывается что у 99% функций такой контракт, и их все надо проверять?

представь что у тебя в коде параметрами функций могут быть только указатели,
т.е. int* add(int* a, int* b) вместо int add(int a, int b)
и ты серьезно говоришь что "тесты должны покрывать *все* случаи, где такие методы функции могут быть задействованы"?
т.е. *каждый* вызов *каждой* функции?

ГВ>Откуда берётся входной obj?

в каждом из 100500 вызовов call_foo — по разному.
аргумент другой функции, поле класса, элемент коллекции — откуда угодно.
In Zen We Trust
Re[13]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 27.10.13 18:28
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Если ты не заметил, то критикую я в основном менеджмент, а не программистов, поскольку задачи и граничные условия их решений ставит именно он.


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

ГВ>Например, мне очень интересно узнать, какие непреодолимые проблемы мешают протестировать Python-программу на заведомо невалидных входных данных?


что ты имеешь ввиду под "невалидными" данными?

ГВ>А... Начинаю понимать. Любые данные в Python могут быть NoneType?

да.
In Zen We Trust
Re[14]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 27.10.13 23:21
Оценка:
Здравствуйте, Abyx, Вы писали:

ГВ>>Если ты не заметил, то критикую я в основном менеджмент, а не программистов, поскольку задачи и граничные условия их решений ставит именно он.

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

Менеджмент ставит задачу сделать такое покрытие. Если менеджменту плевать на стабильность работы софта (или он уповает на какую-нибудь чепуху, типа "синергии", которая "сама" должна привести к нужному результату) — он такой задачи может и не поставить. А если ему не плевать — он её поставит, выделит ресурсы и потребует выполнения.

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

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

В пользу предположения о том, что руководство не озабочивалось таким тестированием, свидетельствует вот эта цитата:

Тесты, которые «покрывают весь код», к сожалению, совсем не покрывают «все возможные типы входных данных» (которые, внезапно, динамические) и совсем не спасают от ошибок типизации.


Понимаешь? "Внезапно"! А виноват в этом кто? Ясное дело — язык программирования.

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

ГВ>>Например, мне очень интересно узнать, какие непреодолимые проблемы мешают протестировать Python-программу на заведомо невалидных входных данных?


A>что ты имеешь ввиду под "невалидными" данными?


Вот псевдокод (я почти уверен, что он моделирует ситуацию из исходной статьи):

var data = inputStream.read();
SomeType typedData = castToSomeType(data);


"Валидными" мы назовём такие данные, которые, будучи прочитаны в переменную data могут быть преобразованы в объект типа SomeType. "Невалидными" — такие, что вызовут... М-м-м... Скажем так, вызовут неожиданности в этом преобразовании. Например, если у нас отключено выбрасывание исключений, typedData примет значение "пусто" (NULL, NIL, nul, None, Empty...), хотя формально, какие-то данные были прочитаны на первом шаге. Это самое "пусто" далее покатится туда, где его не ждут, генерируя разнообразные ошибки.

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

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

Да, говоря о "проверке типа" я имею в виду любую проверку структуры полученных данных, не только какое-нибудь: "String != Int". Например, на входе может быть XML, где в каких-то узлах мы ждём "целые", а оказываются "строки". Схема остаётся прежней.

ГВ>>А... Начинаю понимать. Любые данные в Python могут быть NoneType?

A>да.

Отлично. И как это должно повлиять на мои предыдущие рассуждения?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[15]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 28.10.13 00:09
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>В пользу предположения о том, что руководство не озабочивалось таким тестированием, свидетельствует вот эта цитата:


ГВ>

Тесты, которые «покрывают весь код», к сожалению, совсем не покрывают «все возможные типы входных данных» (которые, внезапно, динамические) и совсем не спасают от ошибок типизации.


ГВ>Понимаешь? "Внезапно"! А виноват в этом кто? Ясное дело — язык программирования.


да. виноват язык программирования, а конкретно динамическая типизация.

ГВ>Вот псевдокод (я почти уверен, что он моделирует ситуацию из исходной статьи):


ГВ>
ГВ>var data = inputStream.read();
ГВ>SomeType typedData = castToSomeType(data);
ГВ>


нет. ты до сих пор не понял что такое "динамическая типизация" и о каких "входных данных" речь.

если тебе близок C#, то код моделирующий проблему выглядит так

void f(dynamic x)
{
    x.m();
}


под "входными данными" понимаются любые входные данные функций (unit'ов) — параметры функций, глобальные переменные — все что unit (класс/функция) получает на вход.
в этом коде "входные данные" это "x".

еще раз, речь не о данных от юзера, или других данных на входе программы.
речь о данных на входе каждого unit'a кода.

и вот автор статьи говорит:
"Тесты, которые «покрывают весь код»" — т.е. тесты покрывающие код f (и вообще любого другого юнита кода),
"не покрывают «все возможные типы входных данных»" — потому что аргументом f может оказаться что угодно,
потому что в ЯП динамические типы данных.

я хз как еще это объяснить %)
все типы аргументов, членов классов, вообще все типы — это "dynamic", и юнит-тесты никак не могут отловить ошибки типизации.
интеграционные тесты для N юнитов не могут отловить ошибки типизации, если система из этих юнитов сводится к f(dynamic x).
только когда в тестируемой системе будут все юниты которые создают все объекты, у нас не будет входных данных с динамическими типами, и мы можем ее протестировать. только такая система будет слишком большой и потому нетестируемой.




ГВ>
ГВ>SomeType typedData = castToSomeType(data);
ГВ>

SomeType это *статический* тип. в языках с динамической типизацией нету статических типов. *вообще нету*. и кастов-к-статическому-типу нету, потому что (внезапно) нету статических типов.
в языках с динамической типизацией у объектов нету статического набора методов. и нельзя сказать "у SomeType всегда есть метод foo".
объект может иметь тип SomeType, но может ему не добавили метод foo, или у него удалили метод foo.
class SomeType: # создали тип
    pass

x = SomeType() # создали объект
x.foo = some_foo # добавили метод
del x.foo # удалили метод
In Zen We Trust
Re[17]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 28.10.13 12:30
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

A>>еще раз, речь не о данных от юзера, или других данных на входе программы.

A>>речь о данных на входе каждого unit'a кода.

A>>и вот автор статьи говорит:

A>>"Тесты, которые «покрывают весь код»" — т.е. тесты покрывающие код f (и вообще любого другого юнита кода),
A>>"не покрывают «все возможные типы входных данных»" — потому что аргументом f может оказаться что угодно,
A>>потому что в ЯП динамические типы данных.

ГВ>Стоп. С этого места я попрошу тебя перестать гнать пургу. "Что угодно" никогда нигде не оказывается, вне зависимости от того, какая типизация используется в данном языке программирования. И вменяемые люди никогда не полагаются на "что угодно". Вот смотри, на вскидку взятый кусок кода из питоновской библиотеки. Этот код ориентирован на враждебный внешний мир, подсовывающий неизвестно, что:


ГВ>
ГВ>def start_new_thread(function, args, kwargs={}):
ГВ>    ...
ГВ>    if type(args) != type(tuple()):
ГВ>        raise TypeError("2nd arg must be a tuple")
ГВ>    if type(kwargs) != type(dict()):
ГВ>        raise TypeError("3rd arg must be a dict")
ГВ>    ...
ГВ>


ГВ>То есть, формально говоря, на вход start_new_thread можно передать что угодно. Но она отсечёт это "что угодно" с исключениями. Ничего неожиданного.


это неудачный пример. в start_new_thread эти проверки только для того чтобы получить красивое сообщение о нарушении контракта, потому что в документации сказано "args must be a tuple".
заметь, что там нет проверки типа параметра "function"
в реальном коде никто не проверяет типы аргументов. (если для этого нет каких-то особых причин)

т.е. никто не пишет код типа
def f(x):
    if not hasattr(x, 'm'): raise AttributeError('...')
    x.m()

потому что эта проверка дублирует работу виртуальной машины Pyhthon'а

ГВ>Точно такой же подход можно применить и в программе пользователя. Можно проверить содержимое атрибутов фактического параметра, можно сократить эти проверки до проверки типа и т.п. Короче говоря, всё как обычно. И тестирование таких функцией, в общем, ничем не отличается от тестирования программ на C, использующих указатели: тестами мы доказываем работоспособность программы и в том числе, её "умение" определять недопустимые комбинации входных данных.


этот подход не дает ничего. Python сам делает все проверки типов и выбрасывает исключения, только немного с другим текстом, типа "NoneType has no attribute m".
написание проверок типов руками позволяет добиться только user-friendly сообщений об ошибках, не более того.

A>>я хз как еще это объяснить %)

A>>все типы аргументов, членов классов, вообще все типы — это "dynamic", и юнит-тесты никак не могут отловить ошибки типизации.

ГВ>Могут. И должны. Потому что если к типу объекта никаких требований не предъявляется, то мы им и не пользуемся и он находится за рамками нашей программы. А если пользуемся (методы там вызываем, атрибуты дёргаем), то нам нужно проверять его характеристики. То есть проверять имена типов, наличие нужных атрибутов у этих типов и т.п. Для статически типизированного языка это делает компилятор, для динамически типизированного — руки программиста. И если мы этого не делаем, то виноват не язык, а... Я уже писал, кто виноват.

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

ГВ>То же самое и с тестами. Должны быть как тесты, имитирующие некорректные входные данные, так и тесты, которые проверяют структуру выходных данных.


тесты *чего*?
юнита? — они не помогают.
всей программы размером в 100500 LOC? — такие тесты всегда не покрывают все случаи. их вообще непонятно как писать %)

A>>интеграционные тесты для N юнитов не могут отловить ошибки типизации, если система из этих юнитов сводится к f(dynamic x).


ГВ>А вот тут я снова чего-то не понимаю. Разве можно создать объект типа dynamic


dynamic x = new System.Dynamic.ExpandoObject();
x.y = 1;
return x.y;


ГВ>Кстати, а разве в Python можно аналогично удалять методы класса (а не объекта)?


можно. "del SomeType.foo"
In Zen We Trust
Re[19]: Менеджер про хаскель в продакшне
От: Sinclair Россия https://github.com/evilguest/
Дата: 29.10.13 05:33
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Ясно, был не прав, хотя в общем — тот же Object, только в профиль. Однако, принципиально это снова ничего не меняет. Потому что дальше к dynamic-объекту всё равно предъявляются вполне определённые требования, например, наличия тех или иных атрибутов. Следовательно, технически, объект может быть dynamic, но функционально всё равно есть некий контракт, которому он должен удовлетворять.

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

Вот у меня функция dynamic getValueOrDefault(this dynamic o, string name, dynamic defaultValue). Она должна возвращать значение по имени из более-менее любого контейнера. Какие тесты будем для неё писать?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[20]: Менеджер про хаскель в продакшне
От: Sinix  
Дата: 29.10.13 06:20
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Вот у меня функция dynamic getValueOrDefault(this dynamic o, string name, dynamic defaultValue). Она должна возвращать значение по имени из более-менее любого контейнера. Какие тесты будем для неё писать?


По-моему, тут проблема не столько в тестах, сколько в самой функции.

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

Масштабируется конечно отвратно, если подобных велосипедов не один и не два — проблемы будут вылезать постоянно.
Re[20]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 29.10.13 08:50
Оценка:
Здравствуйте, Sinclair, Вы писали:

ГВ>>Ясно, был не прав, хотя в общем — тот же Object, только в профиль. Однако, принципиально это снова ничего не меняет. Потому что дальше к dynamic-объекту всё равно предъявляются вполне определённые требования, например, наличия тех или иных атрибутов. Следовательно, технически, объект может быть dynamic, но функционально всё равно есть некий контракт, которому он должен удовлетворять.

S>Осталось понять
S>а) как это формализовать

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

S>б) как это протестировать, не заглядывая внутрь функции.


Тестирование по методу чёрного ящика.

S>Вот у меня функция dynamic getValueOrDefault(this dynamic o, string name, dynamic defaultValue). Она должна возвращать значение по имени из более-менее любого контейнера. Какие тесты будем для неё писать?


Что такое: "более-менее любого"? Так любого или "более-менее"?

И кстати, "this dynamic" первым параметром загнала меня в ступор. Не покажешь объявление поподробней, просто интересно.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[19]: Недостающее третье
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 29.10.13 08:57
Оценка:
A>>всей программы размером в 100500 LOC? — такие тесты всегда не покрывают все случаи. их вообще непонятно как писать %)

ГВ>Значит, нужно в этом вопросе разобраться и синтезировать соответствующее решение. Я не говорю, что это легко, но и как правило, не невозможно.


ГВ>Или признать одно из двух: либо Python (и другие языки с динамической типизацией) принципиально УГ; либо у кого-то "руки не из того места растут". Третьего не дано.


Тут я, разумеется, загнул в полемическом задоре. "Третий" вывод есть, и выглядит он так: "у нас не хватает времени, чтобы разобраться в проблеме и написать нужные тесты". И этот самое третье автоматически переводит внимание с программистов и языков программирования на менеджмент. Дальнейшие рассуждения сводятся к тем, что были сформулированы eao197.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[21]: Менеджер про хаскель в продакшне
От: Sinclair Россия https://github.com/evilguest/
Дата: 29.10.13 11:02
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Извини, что вопросом на вопрос: а как ты формализуешь требования к любым другим функциям/классам/модулям?

При помощи сигнатуры. Ваш К.О.
ГВ>Ну, вот так же и здесь.
А здесь нет "сигнатуры". Ваш К.О.

ГВ>Тестирование по методу чёрного ящика.

А конкретнее?

ГВ>Что такое: "более-менее любого"? Так любого или "более-менее"?

У нас есть только любой. Напомню: типов нет.
Это в статике я бы взял аргументом что-то типа IDictionary<string, T>, и всё сразу стало бы понятно.
А тут может быть что угодно.

ГВ>И кстати, "this dynamic" первым параметром загнала меня в ступор. Не покажешь объявление поподробней, просто интересно.

Это из головы. В реальности не работает — заекстендить любой динамик к счастью нельзя.
На суть не влияет — убери this.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[21]: Менеджер про хаскель в продакшне
От: Sinclair Россия https://github.com/evilguest/
Дата: 29.10.13 11:04
Оценка:
Здравствуйте, Sinix, Вы писали:


S>По-моему, тут проблема не столько в тестах, сколько в самой функции.

Тут — да.
S>Если без динамика никак — остаются тесты по заранее оговорённым вариантам использования, они же документация: что можем обрабатывать — обрабатываем, остальное — на свой страх и риск. Плюс обязательный ассерт, который собирает в лог неподдерживаемые контейнеры.
Это вы так думаете, потому что я сигнатуру на шарпе написал. А если это джаваскрипт? Там нет способа вместо динамика написать что-то более специфичное, или написать перегрузок по типу аргумента.


S>Масштабируется конечно отвратно, если подобных велосипедов не один и не два — проблемы будут вылезать постоянно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[22]: Менеджер про хаскель в продакшне
От: Sinix  
Дата: 29.10.13 12:07
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>>Если без динамика никак — остаются тесты по заранее оговорённым вариантам использования, они же документация: что можем обрабатывать — обрабатываем, остальное — на свой страх и риск. Плюс обязательный ассерт, который собирает в лог неподдерживаемые контейнеры.


S>Это вы так думаете, потому что я сигнатуру на шарпе написал. А если это джаваскрипт? Там нет способа вместо динамика написать что-то более специфичное, или написать перегрузок по типу аргумента.

А тогда ничего не подскажу, наоборот, присоединяюсь к вопросу

Какие ещё варианты могут быть, кроме переезда на typescript?
Re[22]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 29.10.13 14:23
Оценка:
Здравствуйте, Sinclair, Вы писали:

ГВ>>Извини, что вопросом на вопрос: а как ты формализуешь требования к любым другим функциям/классам/модулям?

S>При помощи сигнатуры. Ваш К.О.
ГВ>>Ну, вот так же и здесь.
S>А здесь нет "сигнатуры". Ваш К.О.

O'rly? Проверим.

ГВ>>Тестирование по методу чёрного ящика.

S>А конкретнее?

Щас увидим.

ГВ>>Что такое: "более-менее любого"? Так любого или "более-менее"?

S>У нас есть только любой. Напомню: типов нет.

Отлично. Как ты будешь извлекать объект по имени из контейнера ArrayList<T>?

S>Это в статике я бы взял аргументом что-то типа IDictionary<string, T>, и всё сразу стало бы понятно.

S>А тут может быть что угодно.

ArrayList<T>. Извлеки элемент по имени.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[23]: Менеджер про хаскель в продакшне
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.10.13 04:15
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>ArrayList<T>. Извлеки элемент по имени.

Вас не затруднит определиться, о какой системе типов идёт речь?
В типичных динамиках нет никаких ArrayList<T>. Есть просто массивы. Вот вам функция на JavaScript, которая извлекает то, что мне нужно:
function getValueByName(o, name)
{
  if(Object.prototype.toString.call(o) === '[object Array]' ) {
    for(var i=0;i<o.length;i++)
      if (('name' in o[i]) && (o[i].name == name))
        return o[i];
  return null;
}
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[24]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 30.10.13 10:19
Оценка:
Здравствуйте, Sinclair, Вы писали:

ГВ>>ArrayList<T>. Извлеки элемент по имени.

S>Вас не затруднит определиться, о какой системе типов идёт речь?

Затруднит. Потому что я не собираюсь выполнять за тебя твою часть работы.

S>В типичных динамиках нет никаких ArrayList<T>. Есть просто массивы. Вот вам функция на JavaScript, которая извлекает то, что мне нужно:


"Типичные" — это какие? Синклер, ты, вроде, раньше был не склонен отсылать к универсальным всемогутерам. Что с тобой случилось?

S>
S>function getValueByName(o, name)
S>{
S>  if(Object.prototype.toString.call(o) === '[object Array]' ) {
S>    for(var i=0;i<o.length;i++)
S>      if (('name' in o[i]) && (o[i].name == name))
S>        return o[i];
S>  return null;
S>}
S>


Ну и где здесь "любые" контейнеры? Всё предельно ясно и однозначно: "Object.prototype.toString.call(o) === '[object Array]'"
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[25]: Менеджер про хаскель в продакшне
От: Sinclair Россия https://github.com/evilguest/
Дата: 31.10.13 04:50
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:
ГВ>Затруднит. Потому что я не собираюсь выполнять за тебя твою часть работы.
С чего это она вдруг моя?

ГВ>"Типичные" — это какие? Синклер, ты, вроде, раньше был не склонен отсылать к универсальным всемогутерам. Что с тобой случилось?

Например, JavaScript.

S>>
S>>function getValueByName(o, name)
S>>{
S>>  if(Object.prototype.toString.call(o) === '[object Array]' ) {
S>>    for(var i=0;i<o.length;i++)
S>>      if (('name' in o[i]) && (o[i].name == name))
S>>        return o[i];
S>>  return null;
S>>}
S>>


ГВ>Ну и где здесь "любые" контейнеры? Всё предельно ясно и однозначно: "Object.prototype.toString.call(o) === '[object Array]'"

Э, нет, мы так не договаривались. Тестировать собирались вроде чёрный ящик, нет?
Это вообще может уже оказаться вторая версия. Вот первая версия функции:
function getValueByName(o, name)
{
  for(var i=0;i<o.length;i++)
    if (('name' in o[i]) && (o[i].name == name))
      return o[i];
  return null;
}

Впрочем, это неважно — я жду набора тестов для этой функции. Их же должно быть легко написать, нет?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[26]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 31.10.13 07:10
Оценка:
Здравствуйте, Sinclair, Вы писали:

ГВ>>Затруднит. Потому что я не собираюсь выполнять за тебя твою часть работы.

S>С чего это она вдруг моя?

Ну, ты же подкидываешь задачу, вот ты и конкретизируй условия.

ГВ>>Ну и где здесь "любые" контейнеры? Всё предельно ясно и однозначно: "Object.prototype.toString.call(o) === '[object Array]'"

S>Э, нет, мы так не договаривались. Тестировать собирались вроде чёрный ящик, нет?

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

S>Впрочем, это неважно — я жду набора тестов для этой функции. Их же должно быть легко написать, нет?


Где это я говорил, что их "легко" написать? "Не невозможно" != "легко". Объём тестов запросто может в несколько раз превзойти размер программы.

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

Для первой версии:

1) "o" должен содержать целочисленный атрибут length и оператор []. (По умолчанию: отсутствие одного из этих атрибутов приводит к исключению.)
2) Объект, доступный по индексу [0..o.length-1] может иметь атрибут name (тип значения name не определён, но должен допускать сравнение на эквивалентность с аргументом name). Объекты, у которых name отсутствует, игнорируются.
3) Возвращается первый попавшийся объект, для которого o[i].name == name, порядок обхода не определён (привет, чёрный ящик — мы не знаем, в каком порядке проходит поиск).
4) Тип и структура возвращаемого объекта не изменяются по отношению к объекту, доступному через o[index].
5) Если объектов, удовлетворяющих условиям 2) и 3) обнаружить не удалось, возвращается null.

Для второй версии условие 1) переформулируется:

1) "o" является массивом (прототип — Array). В противном случае функция всегда возвращает null.
Остальные пункты неизменны.

По-моему, отсюда уже должно быть очевидно, как именно можно написать тесты.

И ещё, то, что я отказался писать собственно тесты должно как бы намекать, что тестирование — относительно сложный и трудоёмкий процесс.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[27]: Менеджер про хаскель в продакшне
От: Sinclair Россия https://github.com/evilguest/
Дата: 31.10.13 10:31
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Ну, ты же подкидываешь задачу, вот ты и конкретизируй условия.

Ну вот такие вот условия — какие есть.

ГВ>Да, чёрный ящик. Только "чёрный ящик" вовсе не означает, что мы совсем ничего не знаем о том, какие именно данные можно подавать на вход. Это уже претензия на всемогутер. Так или иначе, но мы должны предполагать какую-то реакцию испытуемой функции на какие-то типы данных.

Отож. Вот только наши предположения могут очень сильно отличаться от того, что там на самом деле.

ГВ>Другое дело, что мы не заморачиваемся отслеживанием и покрытием всех возможных ветвлений внутри самой тестируемой функции.

И это очень плохо, не так ли? Потому, что неотслеженная ветка кода может оказаться критической в реальной эксплуатации.
ГВ>В частном случае, она может быть реализована, например, распараллеливанием поиска, или использовать какие-то эвристики для оптимизации поиска. Да мало ли...
Вот именно. Банально проверить на thread safety — уже нетривиально. Это я про случай, когда типы принимаемых и возвращаемых данных нам точно известны.

ГВ>Где это я говорил, что их "легко" написать? "Не невозможно" != "легко". Объём тестов запросто может в несколько раз превзойти размер программы.

Отож. Но мы же не про тесты "вообще", а про то, чем отличаются тесты в динамике и в статике.

ГВ>Для первой версии:


ГВ>1) "o" должен содержать целочисленный атрибут length и оператор []. (По умолчанию: отсутствие одного из этих атрибутов приводит к исключению.)

ГВ>2) Объект, доступный по индексу [0..o.length-1] может иметь атрибут name (тип значения name не определён, но должен допускать сравнение на эквивалентность с аргументом name). Объекты, у которых name отсутствует, игнорируются.
ГВ>3) Возвращается первый попавшийся объект, для которого o.name == name, порядок обхода не определён (привет, чёрный ящик — мы не знаем, в каком порядке проходит поиск).
ГВ>4) Тип и структура возвращаемого объекта не изменяются по отношению к объекту, доступному через o[index].
ГВ>5) Если объектов, удовлетворяющих условиям 2) и 3) обнаружить не удалось, возвращается null.

Прекрасно. Я стоя аплодирую этой стратегии тестирования: тесты проверяют то, что код делает то, что он делает. Получены путём ревёрс-инжиниринга текста функции; полезность равна примерно нулю. В [i]лучшем случае
тянут на регрессионные тесты, хотя и вряд ли: тестируется не то, на что полагается вызывающий код, а то, что удосужился сообщить о функции автор.
Особенно меня впечатляет пункт 5. Способов передать объект, "не удовлетворяющий условиям 2 и 3" — континуум. Как убедиться в том, что функция корректно обрабатывает данные за пределами области определения?

ГВ>По-моему, отсюда уже должно быть очевидно, как именно можно написать тесты.

"Языком" — очевидно. А руками — нет, неочевидно.
Потому что завтра я добавлю в эту функцию ветку типа
if (Object.prototype.toString.call(o[i]) === '[function]') 
{ 
  var candidate = o[i](name);
  if (candidate != null) 
    return candidate;
}

Потому, что мне понадобилось вместо массива именованных объектов передавать массив генераторов именованных объектов, и всё.
Написанные руками (а не языком) тесты п.5. не смогут ни отследить регрессии, ни покрыть новый код.
ГВ>И ещё, то, что я отказался писать собственно тесты должно как бы намекать, что тестирование — относительно сложный и трудоёмкий процесс.
Это должно как бы намекать на нежелание обосновывать свои максималистские утверждения.

Я к чему это всё?
К тому, что в строготипизированном языке я бы имел две перегрузки этой функции:
public T getValueByName(IEnumerable<T> list, string name) where T: INamedObject
{
   return list.FindFirstOrDefault(o=>o.Name == name));
}

и
public T getValueByName(IEnumerable<Func<string, T>> list, string name) 
{
   return list.Select(f=>f(name)).FindFirstOrDefault(v=>v!=default(T));
}

Само наличие сигнатур убрало бы необходимость писать тесты по п. 1, 2 и большей части п.5.
Вопрос про необходимость тестировать п.3 и остальную половину п.5 (т.е. позитивные и негативные случаи) остаётся открытым: при таком объёме кода легче совершить ошибку в тесте, чем в тестируемом коде.
В динамиках перегрузок нет, зато есть адские всемогуторы типа функции $() в jQuery.
Протестировать функцию Enumerable.Select() на два-три порядка проще, чем $().
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[28]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 31.10.13 11:34
Оценка:
Здравствуйте, Sinclair, Вы писали:

ГВ>>Да, чёрный ящик. Только "чёрный ящик" вовсе не означает, что мы совсем ничего не знаем о том, какие именно данные можно подавать на вход. Это уже претензия на всемогутер. Так или иначе, но мы должны предполагать какую-то реакцию испытуемой функции на какие-то типы данных.

S>Отож. Вот только наши предположения могут очень сильно отличаться от того, что там на самом деле.

Ага, то есть правая рука не ведает, что делает левая. Современная стратегия программирования, чо.

ГВ>>Другое дело, что мы не заморачиваемся отслеживанием и покрытием всех возможных ветвлений внутри самой тестируемой функции.

S>И это очень плохо, не так ли? Потому, что неотслеженная ветка кода может оказаться критической в реальной эксплуатации.

Да, поэтому иной раз метод "белого ящика" предпочтительней.

ГВ>>В частном случае, она может быть реализована, например, распараллеливанием поиска, или использовать какие-то эвристики для оптимизации поиска. Да мало ли...

S>Вот именно. Банально проверить на thread safety — уже нетривиально. Это я про случай, когда типы принимаемых и возвращаемых данных нам точно известны.

Типы данных != алгоритмы их обработки.

ГВ>>Где это я говорил, что их "легко" написать? "Не невозможно" != "легко". Объём тестов запросто может в несколько раз превзойти размер программы.

S>Отож. Но мы же не про тесты "вообще", а про то, чем отличаются тесты в динамике и в статике.

По сути — ничем. Ровно то же самое, что ты говоришь о очередном "внезапном" изменении функциональности применимо и к статически-типизированным языкам. Какая, в пень, разница, изменились инварианты для типов или для данных?

ГВ>>Для первой версии:


[...]

S>Прекрасно. Я стоя аплодирую этой стратегии тестирования: тесты проверяют то, что код делает то, что он делает. Получены путём ревёрс-инжиниринга текста функции; полезность равна примерно нулю. В лучшем случае тянут на регрессионные тесты, хотя и вряд ли: тестируется не то, на что полагается вызывающий код, а то, что удосужился сообщить о функции автор.


А ничего за пределами известного мы никогда протестировать и не сможем. Это как бы альфа и омега тестирования. Собственно, доказательство корректности программ сводится к тому же: свести "неизвестное" к известному и на этом основании сделать какие-то выводы.

Я тебе даже больше скажу: никому не нужны программы, работающие с неизвестными данными. Ну то есть сферическим программистам в вакууме, наверное, они нужны, а вот реальным — совсем нет. И первое, что начинает выяснять программист по отношению к новому API, это какие данные этому API нужны.

S>Особенно меня впечатляет пункт 5. Способов передать объект, "не удовлетворяющий условиям 2 и 3" — континуум. Как убедиться в том, что функция корректно обрабатывает данные за пределами области определения?


Это путь в психушку. Функция не может обрабатывать данные, находящиеся за пределами её области определения. Потому что для неё их не существует. Понимаешь? Не существует. Зиро. Эмпти. Вакуум.

ГВ>>По-моему, отсюда уже должно быть очевидно, как именно можно написать тесты.

S>"Языком" — очевидно. А руками — нет, неочевидно.
S>Потому что завтра я добавлю в эту функцию ветку типа
S>
S>if (Object.prototype.toString.call(o[i]) === '[function]') 
S>{ 
S>  var candidate = o[i](name);
S>  if (candidate != null) 
S>    return candidate;
S>}
S>


И окажешься полным КЮ, если поменяешь инварианты утилитной функции, не объявив об этом в мегафон, и не заготовив соответствующих тестов.

S>Потому, что мне понадобилось вместо массива именованных объектов передавать массив генераторов именованных объектов, и всё.


Да на здоровье. Это лишь расширяет область определения функции.

S>Написанные руками (а не языком) тесты п.5. не смогут ни отследить регрессии, ни покрыть новый код.


Это почему это? У функции появился атрибут name? А насчёт покрытия — да, часть тестов придётся переработать, это нормально.

ГВ>>И ещё, то, что я отказался писать собственно тесты должно как бы намекать, что тестирование — относительно сложный и трудоёмкий процесс.

S>Это должно как бы намекать на нежелание обосновывать свои максималистские утверждения.

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

S>Я к чему это всё?

S>К тому, что в строготипизированном языке я бы имел две перегрузки этой функции:

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

S>В динамиках перегрузок нет, зато есть адские всемогуторы типа функции $() в jQuery.

S>Протестировать функцию Enumerable.Select() на два-три порядка проще, чем $().

O'K, допустим, ты меня убедил в моём максимализме. Остаётся признать принципиальную нетестопригодность программ на JS и как следствие, принципиальную непригодность JS для сколь-нибудь серьёзной работы. Ну а что делать, если даже элементарное тестирование сталкивается с непреодолимыми препятствиями?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[29]: Менеджер про хаскель в продакшне
От: Sinclair Россия https://github.com/evilguest/
Дата: 01.11.13 02:45
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>И окажешься полным КЮ, если поменяешь инварианты утилитной функции, не объявив об этом в мегафон, и не заготовив соответствующих тестов.

Какие ещё инварианты? Это полностью backwards-compatible изменение, с точки зрения корректных данных.
Программы, которые раньше не работали, меня не интересуют — как практика.

ГВ>Да на здоровье. Это лишь расширяет область определения функции.

Вот именно.

ГВ>Это почему это? У функции появился атрибут name? А насчёт покрытия — да, часть тестов придётся переработать, это нормально.

Для того, чтобы их переработать, нужно хотя бы задетектить изменения.

ГВ>Максимализм как раз у тебя, где всё происходит внезапно, и каждый может делать всё, что в голову взбредёт.

Welcome to the real world, Neo.

ГВ>По твоей логике на строготипизированном языке можно начудить ничуть не меньше. Например, ввести "недопустимые" имена, на которые функция всегда должна возвращать null. Что характерно, от последствий таких выкрутасов не уберегут даже строготипизированные языки и, подозреваю, не всегда спасут даже языки с автоматическим доказательством корректности.

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

Просто потому, что тестами нужно проверять ту часть контракта компонента, которая описана в документации. Ту, что описана в коде, проверять не надо. Когда мы видим function foo(a, b), у которой в комментариях сказано "принимает два инта, возвращает инт", то тестер вынужден сесть и проверить это утверждение — потому что иначе однажды в ходе эволюции проекта кодер решит вернуть флоат, и сломает в дальнем углу код, который вовсе не был на это рассчитан.
А когда мы видим int function foo(int a, int b), то корректность используемых типов проверяет компилятор. А вот то, что функция возвращает 0 для a==b, надо проверять руками — ровно до тех пор, пока у нас нет способа записать это утверждение в сигнатуре.

ГВ>O'K, допустим, ты меня убедил в моём максимализме. Остаётся признать принципиальную нетестопригодность программ на JS и как следствие, принципиальную непригодность JS для сколь-нибудь серьёзной работы.

Максималистам — да, ничего другого не остаётся.

ГВ>Ну а что делать, если даже элементарное тестирование сталкивается с непреодолимыми препятствиями?

На выбор — любая суперпозиция из соответствующих волновых функций:
1. Закладывать соответствующие ресурсы в тестирование проектов с использованием JS
2. Стремиться использовать языки с более развитыми системами типов. См. например TypeScript
Ваш К.О.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[30]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 01.11.13 10:16
Оценка:
Здравствуйте, Sinclair, Вы писали:

ГВ>>И окажешься полным КЮ, если поменяешь инварианты утилитной функции, не объявив об этом в мегафон, и не заготовив соответствующих тестов.

S>Какие ещё инварианты? Это полностью backwards-compatible изменение, с точки зрения корректных данных.

Корректных — это каких? Массив функций был вполне допустимым типом входных данных, поиск по которому всегда давал null. Больше того, функции могли быть перемешаны с объектами, содержащими атрибут name.

ГВ>>Да на здоровье. Это лишь расширяет область определения функции.

S>Вот именно.

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

ГВ>>Это почему это? У функции появился атрибут name? А насчёт покрытия — да, часть тестов придётся переработать, это нормально.

S>Для того, чтобы их переработать, нужно хотя бы задетектить изменения.

"Нужно детектить", если мы говорим о внешнем коде и "должны быть известны", если код наш.

ГВ>>Максимализм как раз у тебя, где всё происходит внезапно, и каждый может делать всё, что в голову взбредёт.

S>Welcome to the real world, Neo.

Так мой дорогой, это и есть мерило компетентности специалиста, в том числе и менеджера: способность понизить энтропию подвластных ему процессов. А то знаешь, всё, что угодно можно свести к апелляциям к "real world" и неспособности что-то с этим сделать.

ГВ>>По твоей логике на строготипизированном языке можно начудить ничуть не меньше. Например, ввести "недопустимые" имена, на которые функция всегда должна возвращать null. Что характерно, от последствий таких выкрутасов не уберегут даже строготипизированные языки и, подозреваю, не всегда спасут даже языки с автоматическим доказательством корректности.


S>Геннадий, кривляния вам не идут.


Слегка покривлялся я выше. Тут уже успокоился.

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


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

S>Во-вторых, конечно же языки с "автоматическим доказательством корректности", а точнее с более развитыми системами типов, уберегают от ещё большего количества выкрутасов.


Уберегают, безусловно. Никто с этим не спорил. Изначальная проблема в другом. Мы тут обсуждаем критические высказывания eao197 в адрес менеджера, рассказавшего о переходе на Haskell.

S>Просто потому, что тестами нужно проверять ту часть контракта компонента, которая описана в документации. Ту, что описана в коде, проверять не надо. Когда мы видим function foo(a, b), у которой в комментариях сказано "принимает два инта, возвращает инт", то тестер вынужден сесть и проверить это утверждение — потому что иначе однажды в ходе эволюции проекта кодер решит вернуть флоат, и сломает в дальнем углу код, который вовсе не был на это рассчитан.

S>А когда мы видим int function foo(int a, int b), то корректность используемых типов проверяет компилятор. А вот то, что функция возвращает 0 для a==b, надо проверять руками — ровно до тех пор, пока у нас нет способа записать это утверждение в сигнатуре.

Правильно.

ГВ>>O'K, допустим, ты меня убедил в моём максимализме. Остаётся признать принципиальную нетестопригодность программ на JS и как следствие, принципиальную непригодность JS для сколь-нибудь серьёзной работы.

S>Максималистам — да, ничего другого не остаётся.

А остальные будут есть кактус кормить пользователей кактусами под видом капусты?

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

ГВ>>Ну а что делать, если даже элементарное тестирование сталкивается с непреодолимыми препятствиями?

S>На выбор — любая суперпозиция из соответствующих волновых функций:
S>1. Закладывать соответствующие ресурсы в тестирование проектов с использованием JS
S>2. Стремиться использовать языки с более развитыми системами типов. См. например TypeScript
S>Ваш К.О.

Ну вот, по сути ты другими словами высказал то, что сформулировал eao197 в своём комментарии к статье:

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


И чуть позже пересказал я: http://www.rsdn.ru/forum/philosophy/5346054.1
Автор: Геннадий Васильев
Дата: 29.10.13


Так что, спорить мне с тобой не о чем.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[31]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 02.11.13 19:31
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Мы тут обсуждаем критические высказывания eao197 в адрес менеджера, рассказавшего о переходе на Haskell.


ГВ>

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


в этой ветке темы мы обсуждаем то что eao197 сказал глупые вещи, как то:
— юнит-тесты помогают найти ошибки в типах входных параметров юнита.
— покрытие *строк* кода как-то кореллирует с покрытием вариантов входных данных.
— функциональное тестирование реальной программы покрывает 100% функциональности программы.
— имитационные стенды имитирует все что может случиться с программой в реальности.
In Zen We Trust
Re[32]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 02.11.13 22:35
Оценка:
Здравствуйте, Abyx, Вы писали:

A>в этой ветке темы мы обсуждаем то что eao197 сказал глупые вещи, как то:

A>- юнит-тесты помогают найти ошибки в типах входных параметров юнита.
A>- покрытие *строк* кода как-то кореллирует с покрытием вариантов входных данных.
A>- функциональное тестирование реальной программы покрывает 100% функциональности программы.
A>- имитационные стенды имитирует все что может случиться с программой в реальности.

Повторяю цитату ещё раз:

Да, в языках с динамической типизацией есть такая особенность. [...] единственным способом борьбы с этим явлением является тестирование


Ты можешь предложить другой способ борьбы с ошибками типизации в программах на динамически типизированных языках?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[33]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 02.11.13 22:44
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Здравствуйте, Abyx, Вы писали:


A>>в этой ветке темы мы обсуждаем то что eao197 сказал глупые вещи, как то:

A>>- юнит-тесты помогают найти ошибки в типах входных параметров юнита.
A>>- покрытие *строк* кода как-то кореллирует с покрытием вариантов входных данных.
A>>- функциональное тестирование реальной программы покрывает 100% функциональности программы.
A>>- имитационные стенды имитирует все что может случиться с программой в реальности.

ГВ>Повторяю цитату ещё раз:


ГВ>

Да, в языках с динамической типизацией есть такая особенность. [...] единственным способом борьбы с этим явлением является тестирование


ГВ>Ты можешь предложить другой способ борьбы с ошибками типизации в программах на динамически типизированных языках?


повторюсь еще раз.
юнит-тесты не являются способом борьбы с ошибками типизации

единственным адекватным способом борьбы с ошибками типизации является переход к статической типизации. что они и сделали.
In Zen We Trust
Re[34]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 02.11.13 23:07
Оценка:
Здравствуйте, Abyx, Вы писали:

ГВ>>Ты можешь предложить другой способ борьбы с ошибками типизации в программах на динамически типизированных языках?


A>повторюсь еще раз.

A>юнит-тесты не являются способом борьбы с ошибками типизации

Я не спрашивал, чем являются юнит-тесты. Вопрос был, что делать с программой на динамически типизированном языке, чтобы избавиться от ошибок типизации.

A>единственным адекватным способом борьбы с ошибками типизации является переход к статической типизации. что они и сделали.


Повторюсь:

на динамически типизированных языках


Итак, ты можешь предложить способ решения проблемы, не меняя язык программирования?
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[35]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 03.11.13 09:03
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>>>Ты можешь предложить другой способ борьбы с ошибками типизации в программах на динамически типизированных языках?


A>>повторюсь еще раз.

A>>юнит-тесты не являются способом борьбы с ошибками типизации

ГВ>Я не спрашивал, чем являются юнит-тесты. Вопрос был, что делать с программой на динамически типизированном языке, чтобы избавиться от ошибок типизации.


A>>единственным адекватным способом борьбы с ошибками типизации является переход к статической типизации. что они и сделали.


ГВ>Повторюсь:


ГВ>

на динамически типизированных языках


ГВ>Итак, ты можешь предложить способ решения проблемы, не меняя язык программирования?


нету такого способа. по дизайну языка нету.
In Zen We Trust
Re[36]: Менеджер про хаскель в продакшне
От: Геннадий Васильев Россия http://www.livejournal.com/users/gesha_x
Дата: 04.11.13 11:01
Оценка:
Здравствуйте, Abyx, Вы писали:

ГВ>>Итак, ты можешь предложить способ решения проблемы, не меняя язык программирования?

A>нету такого способа. по дизайну языка нету.

Иными словами, ты не такого способа не видишь (и как представляется, не видит его и автор статьи из топикстарта), хотя и опираешься в своей аргументации только на язык программирования. А eao197, и "ваш покорный слуга" такой способ видят, правда, он подразумевает работу со всем "человеко-машинным" комплексом, в том числе и в таком аспекте, как "организация работ". Способ трудоёмкий, но тем не менее, относительно реалистичный. В то же время, я понимаю, что любые доводы здесь будут разбиваться "контрдоводами", построенными на том, что, грубо говоря, поломать можно любую программу... И так до бесконечности.

В общем, продолжать спор я смысла не вижу. Похоже, что между нами — пропасть.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Re[37]: Менеджер про хаскель в продакшне
От: Abyx Россия  
Дата: 04.11.13 11:34
Оценка:
Здравствуйте, Геннадий Васильев, Вы писали:

ГВ>Способ трудоёмкий, но тем не менее, относительно реалистичный.


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

пока для меня это выглядит так:
— люди не могут летать, нужен самолет т.к. способа летать без крыльев нет.
— А "ваш покорный слуга" такой способ видит, правда, он подразумевает работу со всем "человеко-машинным" комплексом, в том числе и в таком аспекте, как "организация работ". Способ трудоёмкий, но тем не менее, относительно реалистичный

напиши программу с динамической типизацией, тесты к ней, которые отловят все ошибки связанные с типизацией, тогда рассказывай про реалистичные способы.
не обязательно брать python/js. можно взять Си или С# и использовать только типы T* или T? .
(T* является аналогом variant<nullptr_t, T&> так что это простейший случай динамической типизации)
In Zen We Trust
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.