Здравствуйте, landerhigh, Вы писали:
L>Ты перепутал хорошесть машины и хорошесть маркетинга.
Вовсе нет.
Но это уже оч. сильно офтоп...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[39]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, landerhigh, Вы писали:
L>Им вообще остается проверять сборку на соответствие спецификациям, по большому счету.
Если над уровнем юитов нет какого-то сложного их взаимодействия....
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[39]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, _hum_, Вы писали:
L>>>По-твоему получается, что из статьи следует, что все, что я делал последние 10+ лет, сделать было невозможно? Забавно.
__>>нет, это означает, что то, что вы делали за последние десять лет, на самом деле не "проверить, что поведение в принципе соответствует ожидаемому", а "establish that it[system function] does not function properly under specific conditions"
L>
L>Testing cannot establish that a product functions properly under all conditions but can only establish that it does not function properly under specific conditions.
L>Иными словами, это означает, что в случае ЧЯ тестирования тот факт, что система правильно функционирует в условиях, в которых ее тестеры не поленились прогнать, вовсе не гарантирует, что система будет правильно функционировать вообще во всех условиях. С этим никто не спорит. Все возможные условия просто не проверить (комбинаторный взрыв, однако).
L>Но вот тут и приходит понимание того, в чем вся мощь юнит-тестирования.
L>При правильном подходе к организации кода и покрытию сценариев его использования прогаммист может протестировать все сценарии использования юнита. Абсолютно все.
но это же неправда — даже для обычной foo(uint32_t x, uint32_t y) практически невозможно проверить абсолютно все комбинации аргументов/
L>Обычно. Как правило. Чем опытнее TDD-программист, тем сильнее его "обычно" стремится к "всегда". Иногда это не так, иногда это и правда дорого (привет, Erop), иногда просто лень, иногда тупо непонятно, что нужно делать в случае определенных входных данных, которых никогда быть не должно.
вот это уже "ближе к телу". и вроде бы я с вами в этом соглашался — что юнит-тесты (хотя я еще не до конца осознал их суть) позволяют снизить вероятность появления ошибок, но требуют затрат. поэтому всегда нужно смотреть на соотношение цена/качество, а не рассматривать их как панацею и замену дебагера.
L>Что это означает? Что система, состоящая из оттестированных юнитов, в тестировании не нуждается? You wish! Это означает нечто другое, а именно то, что система уже прошла раннюю верификацию. Тестерам не нужно искать сломанное сетевое устройство, чтобы проверить поведение системы в случае общения с устройством, которое портит сообщения, так как логика этого поведения уже проверена. L>Им вообще остается проверять сборку на соответствие спецификациям, по большому счету.
и опять же я в самом начале про это говорил — что там, где разработка ведется методом "взял готовые функциональные блоки, и скомпоновал их нужным образом" — унит-тестирование выглядит выигрышно, а вот там, где ведется непосредственная разработка этих блоков — не совсем.
Re[33]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, _hum_, Вы писали:
L>>>Хмм.. по мне так оно весьма конкретное. Означает — юнит тесты подают на вход тестируемого юнита некие данные и сравнивают отклик с ожидаемым. __>>а, ну вот теперь более конкретно. L>>>Погоди, что запустили? Вот вы начинаете работу над совершенно новым проектом. Твоя задача — реализовать.... ну драйвер сканера (courtesy of Erop). Вот ты пишешь первый класс, уж не знаю, какой. Что ты запускаешь? Ничего запускаемого еще нет и 10 месяцев не будет. Как ты проверишь? __>>да спокойно. возьму и отдельно повызываю его методы на прогонных значениях (ведь прогон же не считается юнит-тестом?)
L>Таак, уже теплее. Вот это "возьму отдельно и повызываю методы" ты как делаешь? Вот новый проект, ничего запускаемого еще нет. Какие действия?
например, CA A; A.foo(0); A.foo(1); A.foo(0.5)// для крайних значений 0, -1 и обычного 0.5
__>>>>не понял что нельзя написать assert(nullptr != data); ?
L>>>Нет, во многих случаях писать его там бессмысленно.
L>Потому что это либо означает, что нужна полноценная проверка в рантайме, либо архитектура плохо продумана, либо ассерт просто воткнут туда "на всякий случай", потому что "так принято".
это означает, что при нормально работающей системе nullptr-а там быть не должно, а вот на этапе разработке, вполне может появиться, и это будет свидетельствовать об ошибке
L>>>>>Чтобы верифицировать поведение do_smth, код ассерта должен полностью реализовывать алгоритм, который он верифицирует. __>>>>ну, то есть, опять же, отличие в невозможности ассерта протестировать именно функциональность (работу функции при всевозможных различных аргументах)? так? L>>>Как минимум, для начала.
__>>ок. спасибо.
L>Это, на самом деле, отличие, которое и отличает каменный век от века полетов в космос
ммм... пока не понял, как именно осуществляется тестирование функциональности (задача вроде неподъемная из-за "комбинаторного взрыва"), и почему его нужно считать качественным шагом вперед. но спасибо за диалог — начало что-то проясняться
Re[35]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, _hum_, Вы писали:
__>>>>так в сложных случаях есть брейк-поинты, когда вместо того, чтобы анализировать весь поток управления, выделяют отдельные его фрагменты, подпадающие под подозрение (с помощью тех же ассертов) L>>>Это тоже крайне простые случаи. __>>а какие сложные? (если не брать во внимание многопроцессные проги)?
L>Многопоточные, наверное? Они, родимые.
не, их в рассмотрение не включаем это отдельная головная боль
L>Да даже и в однопоточной факт наблюдения чертовщины в отладчике вовсе не гарантирует, что она вызвана именно на этом месте в call stack.
это почему же?
Re[39]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, _hum_, Вы писали:
__>>вооот!!!! у вас повилось понятие "шаг" и "лог", а это есть ни что иное, как шаг дебагера и состояние процесса (watched variables)
E>Логи удобнее.
неважно. де-факто вы производите поиск ошибок путем последовательного отслеживания состояний процесса — в точности то, что делает дебагер.
Re[40]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, _hum_, Вы писали:
__>но это же неправда — даже для обычной foo(uint32_t x, uint32_t y) практически невозможно проверить абсолютно все комбинации аргументов/
А все и не нужно... Нужно протестить все границы и ветки, а не все комбинации...
L>>Им вообще остается проверять сборку на соответствие спецификациям, по большому счету.
__>и опять же я в самом начале про это говорил — что там, где разработка ведется методом "взял готовые функциональные блоки, и скомпоновал их нужным образом" — унит-тестирование выглядит выигрышно, а вот там, где ведется непосредственная разработка этих блоков — не совсем.
IMHO всё ровно наоборот. Если есть оттестированные блоки, которые мы компонуем типа, то юнит-тест не много дадут, а вот если мы новые блоки пишем, то там юнит-тесты блоков зело полезны...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[40]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, _hum_, Вы писали:
L>>При правильном подходе к организации кода и покрытию сценариев его использования прогаммист может протестировать все сценарии использования юнита. Абсолютно все. __>но это же неправда — даже для обычной foo(uint32_t x, uint32_t y) практически невозможно проверить абсолютно все комбинации аргументов/
Все комбинации и не надо. Нужно покрыть все сценарии, а их << комбинаций аргументов. Обычно сценариев три — валидные данные, на которых стабильный алгоритм обязан выдавать предсказуемые данные, и сам алгоритм доказуем по индукции, невалидные данные, на которых должен случаться предсказуемый облом и граничные данные, что есть проверка работы алгоритма на границах применимости, экстремумах и т.п.
L>>Обычно. Как правило. Чем опытнее TDD-программист, тем сильнее его "обычно" стремится к "всегда". Иногда это не так, иногда это и правда дорого (привет, Erop), иногда просто лень, иногда тупо непонятно, что нужно делать в случае определенных входных данных, которых никогда быть не должно.
__>вот это уже "ближе к телу". и вроде бы я с вами в этом соглашался — что юнит-тесты (хотя я еще не до конца осознал их суть) позволяют снизить вероятность появления ошибок, но требуют затрат. поэтому всегда нужно смотреть на соотношение цена/качество, а не рассматривать их как панацею и замену дебагера.
Не требуют они затрат. Пишутся на автомате.
__>и опять же я в самом начале про это говорил — что там, где разработка ведется методом "взял готовые функциональные блоки, и скомпоновал их нужным образом" — унит-тестирование выглядит выигрышно, а вот там, где ведется непосредственная разработка этих блоков — не совсем.
Юнит-тесты применяются в основном как раз для тестирования этих самых блоков при их разработке. Любое другое тестирование при этом выглядит проигрышно.
Re[36]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, _hum_, Вы писали:
L>>Многопоточные, наверное? Они, родимые. __>не, их в рассмотрение не включаем это отдельная головная боль
А вот надо включать, чтобы головную боль как можно раньше отгильотинить
L>>Да даже и в однопоточной факт наблюдения чертовщины в отладчике вовсе не гарантирует, что она вызвана именно на этом месте в call stack. __>это почему же?
Ну тут уже упоминали такую приятную вещь, как стрельбу по памяти, например.
Re[41]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, _hum_, Вы писали:
__>>но это же неправда — даже для обычной foo(uint32_t x, uint32_t y) практически невозможно проверить абсолютно все комбинации аргументов/
E>А все и не нужно... Нужно протестить все границы и ветки, а не все комбинации...
во-первых, что такое "границы" ? граничные точки области определения функции? и почему именно в них нужно, а в других точках — не нужно?
а во-вторых, таких граничных точек может быть тоже неподъемно много для обычных вычислений
L>>>Им вообще остается проверять сборку на соответствие спецификациям, по большому счету.
__>>и опять же я в самом начале про это говорил — что там, где разработка ведется методом "взял готовые функциональные блоки, и скомпоновал их нужным образом" — унит-тестирование выглядит выигрышно, а вот там, где ведется непосредственная разработка этих блоков — не совсем.
E>IMHO всё ровно наоборот. Если есть оттестированные блоки, которые мы компонуем типа, то юнит-тест не много дадут, а вот если мы новые блоки пишем, то там юнит-тесты блоков зело полезны...
если проводить аналогию, то юнит-тесты позволят при компоновке электронных блоков отследить перегрузки на входах и выходах.
Re[34]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, _hum_, Вы писали:
__>>>да спокойно. возьму и отдельно повызываю его методы на прогонных значениях (ведь прогон же не считается юнит-тестом?) L>>Таак, уже теплее. Вот это "возьму отдельно и повызываю методы" ты как делаешь? Вот новый проект, ничего запускаемого еще нет. Какие действия? __>например, CA A; A.foo(0); A.foo(1); A.foo(0.5)// для крайних значений 0, -1 и обычного 0.5
То есть пишете маленький лончер и запускаете его в отладчике? Поздравляю, вы изобрели юнит-тесты вручную! (Бурные продолжительные аплодисменты, переходящие в овацию.)
Серьезно, все, что вы делаете в отладчике, можно и нужно делать автоматически в коде теста. Потом, через полгода, когда будете править код, сами себе спасибо скажете, и не один раз, а когда новонанятый джун "улучшит" уже "отлаженный" код, скажете еще миллион раз.
__>>>>>не понял что нельзя написать assert(nullptr != data); ? L>>>>Нет, во многих случаях писать его там бессмысленно. L>>Потому что это либо означает, что нужна полноценная проверка в рантайме, либо архитектура плохо продумана, либо ассерт просто воткнут туда "на всякий случай", потому что "так принято". __>это означает, что при нормально работающей системе nullptr-а там быть не должно, а вот на этапе разработке, вполне может появиться, и это будет свидетельствовать об ошибке
При TDD выделенное почему-то — редкость.
__>>>ок. спасибо.
L>>Это, на самом деле, отличие, которое и отличает каменный век от века полетов в космос
__>ммм... пока не понял, как именно осуществляется тестирование функциональности (задача вроде неподъемная из-за "комбинаторного взрыва"), и почему его нужно считать качественным шагом вперед. но спасибо за диалог — начало что-то проясняться
Функциональность в первую и вторую очередь определяется сценариями, которые реализуют юниты в отдельности. Хорошо изолированные юниты реально полностью провалидировать в отдельности конечным числом юнитов. Когда они уже склеены в систему, сделать это невозможно из-за комбинаторного взрыва, а вот по отдельности — пожалуйста.
Re[41]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, Erop, Вы писали:
E>IMHO всё ровно наоборот. Если есть оттестированные блоки, которые мы компонуем типа, то юнит-тест не много дадут, а вот если мы новые блоки пишем, то там юнит-тесты блоков зело полезны...
Это, давай лучше про ракеты
Re[42]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, _hum_, Вы писали:
__>во-первых, что такое "границы" ? граничные точки области определения функции? и почему именно в них нужно, а в других точках — не нужно?
Экстремумы, точки перегиба, границы применимости алгоритма. Или тупо все if или switch..case.
__>а во-вторых, таких граничных точек может быть тоже неподъемно много для обычных вычислений
Не может, иначе реализация такого алгоритма займет бесконечное время.
__>если проводить аналогию, то юнит-тесты позволят при компоновке электронных блоков отследить перегрузки на входах и выходах.
Нет, юнит-тесты — это когда каждый транзистор проверяется на конвеере на фабрике еще до того, как ты поставишь его в схему
Re[41]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, _hum_, Вы писали:
L>>>При правильном подходе к организации кода и покрытию сценариев его использования прогаммист может протестировать все сценарии использования юнита. Абсолютно все. __>>но это же неправда — даже для обычной foo(uint32_t x, uint32_t y) практически невозможно проверить абсолютно все комбинации аргументов/
L>Все комбинации и не надо. Нужно покрыть все сценарии, а их << комбинаций аргументов. Обычно сценариев три — валидные данные, на которых стабильный алгоритм обязан выдавать предсказуемые данные, и сам алгоритм доказуем по индукции, невалидные данные, на которых должен случаться предсказуемый облом и граничные данные, что есть проверка работы алгоритма на границах применимости, экстремумах и т.п.
вот этого я и не понимаю. если вы проверили sqrt(uint32_t x) для валидного данного x = 2, то это не значит, что для x = 101 все будет работать, ведь у вас может, например, из-за округлений, или ошибки в программе, которая не проявляет себя на четных числах, перестать работать. скорее уж нужно использовать случайное тестирование (случайным образом выбирается точка в пространтсве аргументов и производится тест для нее)
L>>>Обычно. Как правило. Чем опытнее TDD-программист, тем сильнее его "обычно" стремится к "всегда". Иногда это не так, иногда это и правда дорого (привет, Erop), иногда просто лень, иногда тупо непонятно, что нужно делать в случае определенных входных данных, которых никогда быть не должно.
__>>вот это уже "ближе к телу". и вроде бы я с вами в этом соглашался — что юнит-тесты (хотя я еще не до конца осознал их суть) позволяют снизить вероятность появления ошибок, но требуют затрат. поэтому всегда нужно смотреть на соотношение цена/качество, а не рассматривать их как панацею и замену дебагера.
L>Не требуют они затрат. Пишутся на автомате.
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, _hum_, Вы писали:
L>>>Многопоточные, наверное? Они, родимые. __>>не, их в рассмотрение не включаем это отдельная головная боль
L>А вот надо включать, чтобы головную боль как можно раньше отгильотинить
L>>>Да даже и в однопоточной факт наблюдения чертовщины в отладчике вовсе не гарантирует, что она вызвана именно на этом месте в call stack. __>>это почему же?
L>Ну тут уже упоминали такую приятную вещь, как стрельбу по памяти, например.
а можно на пальцах, для тех, кто далек от "стрельбы по памяти"?
Re[35]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, _hum_, Вы писали:
__>>>>да спокойно. возьму и отдельно повызываю его методы на прогонных значениях (ведь прогон же не считается юнит-тестом?) L>>>Таак, уже теплее. Вот это "возьму отдельно и повызываю методы" ты как делаешь? Вот новый проект, ничего запускаемого еще нет. Какие действия? __>>например, CA A; A.foo(0); A.foo(1); A.foo(0.5)// для крайних значений 0, -1 и обычного 0.5
L>То есть пишете маленький лончер и запускаете его в отладчике? Поздравляю, вы изобрели юнит-тесты вручную! (Бурные продолжительные аплодисменты, переходящие в овацию.) L>Серьезно, все, что вы делаете в отладчике, можно и нужно делать автоматически в коде теста. Потом, через полгода, когда будете править код, сами себе спасибо скажете, и не один раз, а когда новонанятый джун "улучшит" уже "отлаженный" код, скажете еще миллион раз.
понятно. непонятно другое, почему такая достатчно неформальная вещь (выбор значений для тестирования — от балды) вызывает такую бурю восторга? или я еще чего-то не допонял?
Re[40]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, _hum_, Вы писали:
E>>Логи удобнее.
__>неважно. де-факто вы производите поиск ошибок путем последовательного отслеживания состояний процесса — в точности то, что делает дебагер.
Ну так "косяки" могут начать проявляться не с первой итерации...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[42]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, _hum_, Вы писали:
__>во-первых, что такое "границы" ?
Параметры, при которых меняется работа функции. Ветвления иначе происходят, переполнения и т. д...
__>а во-вторых, таких граничных точек может быть тоже неподъемно много для обычных вычислений
Ну тут от функции зависит.
Обычно у нормальных функций это не так...
__>если проводить аналогию, то юнит-тесты позволят при компоновке электронных блоков отследить перегрузки на входах и выходах.
Скорее гарантируют соответствие блоков номиналам
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[43]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, _hum_, Вы писали:
__>>во-первых, что такое "границы" ? граничные точки области определения функции? и почему именно в них нужно, а в других точках — не нужно?
L>Экстремумы, точки перегиба, границы применимости алгоритма. Или тупо все if или switch..case.
почему именно они? почему не другие точки? и что такое "экстремум", "точка перегиба" например, для алгоритма обращения списка?
__>>а во-вторых, таких граничных точек может быть тоже неподъемно много для обычных вычислений
L>Не может, иначе реализация такого алгоритма займет бесконечное время.
да легко может, если вы про обычные граничные точки в математическом понимании. например:
вычисления комплексного значения z по итерационной формуле z_n = z_{n-1} ^2 + c, где с = — 0.74543 + 0.11301i
точки, в которых алгоритм не расходится — так называемое множество жюлиа:
__>>если проводить аналогию, то юнит-тесты позволят при компоновке электронных блоков отследить перегрузки на входах и выходах.
L>Нет, юнит-тесты — это когда каждый транзистор проверяется на конвеере на фабрике еще до того, как ты поставишь его в схему
нет, как я понял, юнит тесты идут в связке с блоками, чтоб я мог при использовании их проверить, все ли в порядке.
Re[41]: Долгая компиляция на с++ - смерть для больших проект
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, _hum_, Вы писали:
E>>>Логи удобнее.
__>>неважно. де-факто вы производите поиск ошибок путем последовательного отслеживания состояний процесса — в точности то, что делает дебагер.
E>Ну так "косяки" могут начать проявляться не с первой итерации...
это уже другой вопрос — как локализовать область появления расхождения ожидаемого от реального