Юнит-тесты уже становятся параноей, в 99% они превращаются в тестирование сеттеров и геттеров и код типа Assert.AreEqual(2+2, 4). Ну или еще очень модно тестировать всякие "бизнес-методы" типа GetCustomerByID , которые неявно превращаются в тестирование движка БД.
Я уже не говорю, что юнит-тесты значительно усложняют доработки в системе, потому что любая доработка становится ГЕМОРРОЕМ, надо перерабатывать и рефакторить кучу тестов, и value от юнит-тестов начинает асимптотически стремится к нулю. Также юнит-тесты привносят кучу неявных contracts, т.е. любой метод, который я хотел бы скрыть и доработать по мере необходимости, становится "public contract" и на него появляются внешние зависимости.
Функциональные тесты куда как более ценны, хотя и с ними тоже нужно знать меру.
Короче, никакие тесты не сделают из плохого кода хороший и не уменьшат стоимость разработки просто от их наличия. Пишите лучше код, следите за руками, думайте о коде и нанимайте хороших ручных тестировщиков — которые, конечно, должны в коде хотя бы приблизительно разбираться.
Здравствуйте, landerhigh, Вы писали:
l> Потому что тема больно общая. l> Вчера наткнулся на это (вроде не баян). ППКС, так как я сам test infected. Программистам смотреть обязательно, вне зависимости от языка и платформы.
Здравствуйте, iHateLogins, Вы писали:
HL>Юнит-тесты уже становятся параноей, в 99% они превращаются в тестирование сеттеров и геттеров и код типа Assert.AreEqual(2+2, 4).
Не читал, но осуждаю, да?
Если Вы не умеете их готовить, то это вовсе не значит, что все не умеют.
Здравствуйте, landerhigh, Вы писали:
HL>>Юнит-тесты уже становятся параноей, в 99% они превращаются в тестирование сеттеров и геттеров и код типа Assert.AreEqual(2+2, 4). L>Не читал, но осуждаю, да?
L>Если Вы не умеете их готовить, то это вовсе не значит, что все не умеют.
Да я не осуждаю сами юнит-тесты, идея-то неплохая в общем, и для ряда задач очень нужная. Для парсеров, компиляторов итд. Для ERP-барахла, однако, где, как тут недавно говорили, 2+2 не всегда равно 4, юнит-тесты очень часто оказываются пустой тратой времени. Не всегда, но очень часто.
Здравствуйте, iHateLogins, Вы писали:
L>>Если Вы не умеете их готовить, то это вовсе не значит, что все не умеют. HL>Да я не осуждаю сами юнит-тесты, идея-то неплохая в общем, и для ряда задач очень нужная. Для парсеров, компиляторов итд. Для ERP-барахла, однако, где, как тут недавно говорили, 2+2 не всегда равно 4, юнит-тесты очень часто оказываются пустой тратой времени. Не всегда, но очень часто.
В этой презентухе как раз основное внимание уделено всем тем мифом, что ты привел в своем посте. В том числе и по геттерам прошлись и иже с ними.
Здравствуйте, landerhigh, Вы писали:
L>Потому что тема больно общая.
L>Вчера наткнулся на это (вроде не баян). ППКС, так как я сам test infected. Программистам смотреть обязательно, вне зависимости от языка и платформы.
Они бы ещё в этой презентации каждую букву на отдельный слайд вынесли
Здравствуйте, neFormal, Вы писали:
F>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О.
Прочитал сначала это, потом твою подпись. Глубоко задумался.
Здравствуйте, landerhigh, Вы писали:
F>>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О. L>Прочитал сначала это, потом твою подпись. Глубоко задумался.
Здравствуйте, neFormal, Вы писали:
F>это хорошо, что возражений не последовало..
А тема не для этого. С теми, кому "тесты писать некогда, копать надо", спорить бесполезно.
Здравствуйте, landerhigh, Вы писали:
F>>это хорошо, что возражений не последовало.. L>А тема не для этого. С теми, кому "тесты писать некогда, копать надо", спорить бесполезно.
заметь, я этого не говорил..
вот так потихоньку и откроются все проблемы авто-тестов
Здравствуйте, landerhigh, Вы писали:
L>>>Если Вы не умеете их готовить, то это вовсе не значит, что все не умеют. HL>>Да я не осуждаю сами юнит-тесты, идея-то неплохая в общем, и для ряда задач очень нужная. Для парсеров, компиляторов итд. Для ERP-барахла, однако, где, как тут недавно говорили, 2+2 не всегда равно 4, юнит-тесты очень часто оказываются пустой тратой времени. Не всегда, но очень часто. L>В этой презентухе как раз основное внимание уделено всем тем мифом, что ты привел в своем посте. В том числе и по геттерам прошлись и иже с ними.
Видно, что презу писал какой-то дебиловатый скрум-мастер или тренер, который сам код не трогал и не писал и не представляет себе, что применимость юнит-тестов сильно зависит от предметной области.
Одно дело — реализация спеки какого-то стандарта, которая (реализация) будет черным ящиком. Пример — парсер XML, XSLT, регекспов. Реализаций куча — спека одна. Другое дело — это "бузинесс"-"методы" GetCustomerById, который состоит из вызова "select * from Customer where CustomerID = @id", в котором тестировать НЕЧЕГО. Ну т.е. конечно можно протестировать что он возвращает кастомеров с ID=3, ID=1, поддерживает отрицательные ID, в результате есть такие-то колонки итд. Но усилий по написанию и, главное, поддержке вы потратите гораздо больше, чем если просто откроете site.com/Customers/1 и убедитесь, что оно не валится. Ну или заскиптуете каким-нить веб-кликером за 5 секунд. Или просто Вася зайдёт на страничку и убедится, что не валится.
Короче, Шура, пишите, пишите тесты. Только потом не возмущайтесь, добавление колонки в базу стало СВЕРХ-СЛОЖНЫМ ИНЖЕНЕРНЫМ ПРОЕКТОМ.
Здравствуйте, landerhigh, Вы писали:
L>В том числе и по геттерам прошлись и иже с ними.
вроде единственное упоминание get/set было о том, что не стоит их обкладывать тестами, чтобы повысить "покрытие кода тестами"..
как то несерьёзно даже..
Здравствуйте, landerhigh, Вы писали:
F>>это хорошо, что возражений не последовало.. L>А тема не для этого. С теми, кому "тесты писать некогда, копать надо", спорить бесполезно.
Также бесполезно спорить с людьми, которые вместо того, чтобы копать (заметьте — не решать дифуры, не искать нефть, а именно копать) начинают "тестировать лопату" каждые 15 минут, проверять схемы экскаватора, цементируют яму бетоном (для надёжности), хотя знают, что завтра бетон придётся вытаскивать обратно.
Имхо, всё это — естественная реакция. ИТ так далеко шагнуло за последние 10 лет, что, если писать эффективные программы ЭФФЕКТИВНО, толпу всякой около-итной шушеры придётся гнать взашей. Вот они и держутся, как могут. И начинается... простейшие сайтики становятся сложнейшими инжереными проектами с командой поддержки в 20-30 человек, вместо простых селектов в базе накручиваются просто МЕГАТОННЫ всякого водопроводного (plumbing) говно-кода, фреймворки над фреймворками... а дальше начинается... добавить колонку? СЛОЖНЕЙШАЯ ЗАДАЧА! Переработать модуль? Да проще новый написать, желательно даже не модуль, а проект с нуля, потому что разобраться в тоннах запутанного кода с десятками тысяч никому не нужных юнит-тестов становится просто невозможно.
Здравствуйте, iHateLogins, Вы писали:
L>>В этой презентухе как раз основное внимание уделено всем тем мифом, что ты привел в своем посте. В том числе и по геттерам прошлись и иже с ними.
HL>Одно дело — реализация спеки какого-то стандарта, которая (реализация) будет черным ящиком. Пример — парсер XML, XSLT, регекспов. Реализаций куча — спека одна.
Ага, тестировать надо только публичный API.
HL> Другое дело — это "бузинесс"-"методы" GetCustomerById, который состоит из вызова "select * from Customer where CustomerID = @id", в котором тестировать НЕЧЕГО. Ну т.е. конечно можно протестировать что он возвращает кастомеров с ID=3, ID=1, поддерживает отрицательные ID, в результате есть такие-то колонки итд. Но усилий по написанию и, главное, поддержке вы потратите гораздо больше, чем если просто откроете site.com/Customers/1 и убедитесь, что оно не валится. Ну или заскиптуете каким-нить веб-кликером за 5 секунд. Или просто Вася зайдёт на страничку и убедится, что не валится.
Из презентации:
Test only that API exposes.
В GetCustomerById, если это часть public API, тестируется маппинг объектов. Доступ к БД мокируется. Если такой тест трудно написать, значит в этом методе проблемы и само намерение написать тест уже показало это.
Если приходится тестировать закрытый метод, то это в 99% случаев значит что этот метод должен быть открытым в другом классе.
HL>Короче, Шура, пишите, пишите тесты. Только потом не возмущайтесь, добавление колонки в базу стало СВЕРХ-СЛОЖНЫМ ИНЖЕНЕРНЫМ ПРОЕКТОМ.
Здравствуйте, Vladek, Вы писали:
V>Ага, тестировать надо только публичный API.
Я ведь не Микрософт — у меня нет "кастомеров" моего API, кроме меня (или моей команды). Я не продаю свою либу. Что в этом случае значит публичный API? Просто public методы? Дык я их создавал не для каких-то абстрактных разработчиков, а конкретно для своего проекта.
HL>> Другое дело — это "бузинесс"-"методы" GetCustomerById, который состоит из вызова "select * from Customer where CustomerID = @id", в котором тестировать НЕЧЕГО. Ну т.е. конечно можно протестировать что он возвращает кастомеров с ID=3, ID=1, поддерживает отрицательные ID, в результате есть такие-то колонки итд. Но усилий по написанию и, главное, поддержке вы потратите гораздо больше, чем если просто откроете site.com/Customers/1 и убедитесь, что оно не валится. Ну или заскиптуете каким-нить веб-кликером за 5 секунд. Или просто Вася зайдёт на страничку и убедится, что не валится.
V>Из презентации: V>
Test only that API exposes.
См. выше.
V>В GetCustomerById, если это часть public API, тестируется маппинг объектов. Доступ к БД мокируется. Если такой тест трудно написать, значит в этом методе проблемы и само намерение написать тест уже показало это.
В том-то и дело, что в реальных ERP-системах запросы чрезвычайно сложны. И если при тестировании Hello World мы огребаем по полной, то нафига нам вообще весь этот гемор с маперами, моками, тестами? Всё равно почти весь код сидит в БД, завязан на БД и жить не может без БД. Реализация же всего на C# только для целей тестирования — это, во-первых, безумно неэффективно с точки зрения производительности (база всё равно будет быстрее в ERP),а, во-вторых, это усложняет архитектуру систему в буквально десятки раз.
V>Если приходится тестировать закрытый метод, то это в 99% случаев значит что этот метод должен быть открытым в другом классе.
HL>>Короче, Шура, пишите, пишите тесты. Только потом не возмущайтесь, добавление колонки в базу стало СВЕРХ-СЛОЖНЫМ ИНЖЕНЕРНЫМ ПРОЕКТОМ. V>Ну я говорю, с маппингом проблемы.
Проблема не в маппинге, конечно. Проблема в API. Если API — это black box, unit-тестирование рулит, если это примитивные методы типа GetCustomerByID или супер-навороченные запросы, вы можете просто убиться для того, чтобы их протестировать. И даже в этом случае в этом не будет смысла.
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, Vladek, Вы писали:
V>>Ага, тестировать надо только публичный API.
HL>Я ведь не Микрософт — у меня нет "кастомеров" моего API, кроме меня (или моей команды). Я не продаю свою либу. Что в этом случае значит публичный API? Просто public методы? Дык я их создавал не для каких-то абстрактных разработчиков, а конкретно для своего проекта.
А как одна подсистема общается с другой? Я вот могу выделить пять подсистем в бизнес-приложении: Presentation (пользовательский интерфейс), Application (бизнес-логика), Infrastructure (бизнес-правила), Configuration (конфигурация, определяет какие бизнес-правила будут действовать), DataAccess (бизнес-объекты, маппинг) и DataSource (хранение данных) часто объединены. Все они общаются друг с другом посредством API, который надо проектировать и лучше делать это осознанно, с использованием тестов.
V>>В GetCustomerById, если это часть public API, тестируется маппинг объектов. Доступ к БД мокируется. Если такой тест трудно написать, значит в этом методе проблемы и само намерение написать тест уже показало это.
HL>В том-то и дело, что в реальных ERP-системах запросы чрезвычайно сложны. И если при тестировании Hello World мы огребаем по полной, то нафига нам вообще весь этот гемор с маперами, моками, тестами? Всё равно почти весь код сидит в БД, завязан на БД и жить не может без БД. Реализация же всего на C# только для целей тестирования — это, во-первых, безумно неэффективно с точки зрения производительности (база всё равно будет быстрее в ERP),а, во-вторых, это усложняет архитектуру систему в буквально десятки раз.
HL>Проблема не в маппинге, конечно. Проблема в API. Если API — это black box, unit-тестирование рулит, если это примитивные методы типа GetCustomerByID или супер-навороченные запросы, вы можете просто убиться для того, чтобы их протестировать. И даже в этом случае в этом не будет смысла.
Если писать приложения в стиле "сдал и забыл", то наверное. Последние четыре проекта, в которых я участвовал, были полным переделыванием такого творчества с нуля.
Здравствуйте, landerhigh, Вы писали:
L>Потому что тема больно общая.
L>Вчера наткнулся на это (вроде не баян). ППКС, так как я сам test infected. Программистам смотреть обязательно, вне зависимости от языка и платформы.
Не осилил постоянно жать на кнопку, чтобы увидеть очередную "мудрость". Это для людей с дислексией сделано — не больше 10 символов одновременно на экране? ))
Какой-то бездельничающий графоман склепал презентацию с претензией на нужность и полезность. И с потугами на "юмор". На мой взгляд, мусор полнейший.
Здравствуйте, landerhigh, Вы писали:
L>Потому что тема больно общая.
L>Вчера наткнулся на это (вроде не баян). ППКС, так как я сам test infected. Программистам смотреть обязательно, вне зависимости от языка и платформы.
L>Вчера наткнулся на это (вроде не баян). ППКС, так как я сам test infected. Программистам смотреть обязательно, вне зависимости от языка и платформы.
Тесты — дело хорошее, но. Сроки и бюджеты для нехайтек проектов порой берутся с потолка. Поэтому работают все в спешке. Получается дилема: (система с тестами, но недоделанная ИЛИ система без тестов, но имеющая всю функциональность, кое как протестированную). Очевидно, всегда годится второй вариант. Если это состояние достигнуто, можно систему впарить и исправить баги уже за доп. деньги.
Клёво, конечно, работать в каком-нибудь гугле, который может себе позволить выпускать качественные продукты. Но в reallife продукты некачественные.
Удвой число ошибок, если не получается добиться цели.
Здравствуйте, Vladek, Вы писали:
V>>>Ага, тестировать надо только публичный API.
HL>>Я ведь не Микрософт — у меня нет "кастомеров" моего API, кроме меня (или моей команды). Я не продаю свою либу. Что в этом случае значит публичный API? Просто public методы? Дык я их создавал не для каких-то абстрактных разработчиков, а конкретно для своего проекта.
V>А как одна подсистема общается с другой? Я вот могу выделить пять подсистем в бизнес-приложении: Presentation (пользовательский интерфейс), Application (бизнес-логика), Infrastructure (бизнес-правила), Configuration (конфигурация, определяет какие бизнес-правила будут действовать), DataAccess (бизнес-объекты, маппинг) и DataSource (хранение данных) часто объединены. Все они общаются друг с другом посредством API, который надо проектировать и лучше делать это осознанно, с использованием тестов.
Я не знаю, что за прикладу ты писал, но подозреваю, что ты малость переусложнил. Подозреваю, что добавление просто новой сущности в БД у тебя приведёт к написанию ДЕСЯТКОВ, если не СОТЕН всяких разнообразных классов. Бедные заказчики, которым под соусом "правильной" разработки подсунули фигню, которую, чтобы "правильно" поддерживать, надо писать ТОННЫ всякого plumbing кода.
V>>>В GetCustomerById, если это часть public API, тестируется маппинг объектов. Доступ к БД мокируется. Если такой тест трудно написать, значит в этом методе проблемы и само намерение написать тест уже показало это.
HL>>В том-то и дело, что в реальных ERP-системах запросы чрезвычайно сложны. И если при тестировании Hello World мы огребаем по полной, то нафига нам вообще весь этот гемор с маперами, моками, тестами? Всё равно почти весь код сидит в БД, завязан на БД и жить не может без БД. Реализация же всего на C# только для целей тестирования — это, во-первых, безумно неэффективно с точки зрения производительности (база всё равно будет быстрее в ERP),а, во-вторых, это усложняет архитектуру систему в буквально десятки раз.
HL>>Проблема не в маппинге, конечно. Проблема в API. Если API — это black box, unit-тестирование рулит, если это примитивные методы типа GetCustomerByID или супер-навороченные запросы, вы можете просто убиться для того, чтобы их протестировать. И даже в этом случае в этом не будет смысла.
V>Если писать приложения в стиле "сдал и забыл", то наверное. Последние четыре проекта, в которых я участвовал, были полным переделыванием такого творчества с нуля.
В том-то и дело, что проще всего поддерживаются приложения, которые ПРОЩЕ написаны! Не те, у которых есть 150 уровней абстракции, фабрики фабрик и которые расстрелены при помощи IoC, а которые сделаны ПРОСТО. Такие поддерживать — просто одно удовольствие.
Минус за то, что забыли покрыть юнит-тестами открывание ссылки в разных браузерах.
Ни IE7, ни Safari4 не смогли открыть эту ботву — там mime-тип не указан, а xml по-человечески не рендерится.
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, Anton Batenev, Вы писали:
AB>>Эм. А ссылка правильная? А то у меня вот это :\ L>Правильная. Попробуй в лисе.
Нету лисы, вырвал с корнями из системы.
Есть в более фф-независимом формате?
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, Кодт, Вы писали:
К>Ни IE7, ни Safari4 не смогли открыть эту ботву — там mime-тип не указан, а xml по-человечески не рендерится.
Это, мопед не мой.
Похоже, это какой-то доморощеный транслятор ppt->html
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, Кодт, Вы писали:
К>>Ни IE7, ни Safari4 не смогли открыть эту ботву — там mime-тип не указан, а xml по-человечески не рендерится. L>Это, мопед не мой. L>Похоже, это какой-то доморощеный транслятор ppt->html
Ей-богу, лучше бы выложили ppt.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, iHateLogins, Вы писали:
HL>Также бесполезно спорить с людьми, которые вместо того, чтобы копать (заметьте — не решать дифуры, не искать нефть, а именно копать) начинают "тестировать лопату" каждые 15 минут, проверять схемы экскаватора, цементируют яму бетоном (для надёжности), хотя знают, что завтра бетон придётся вытаскивать обратно.
Вы не знаете, что такое Юнит-тесты, для чего они нужны и как ими правильно пользоваться. Это случается, когда тестирование на проекте внедряется указанием сверху. HL>вместо простых селектов в базе накручиваются просто МЕГАТОННЫ всякого водопроводного (plumbing) говно-кода, фреймворки над фреймворками... а дальше начинается... добавить колонку? СЛОЖНЕЙШАЯ ЗАДАЧА! Переработать модуль? Да проще новый написать, желательно даже не модуль, а проект с нуля, потому что разобраться в тоннах запутанного кода с десятками тысяч никому не нужных юнит-тестов становится просто невозможно.
Замечательно. Отличный пример разработки класса "надо копать".
Возражения по существу будут?
Здравствуйте, landerhigh, Вы писали:
L>Потому что тема больно общая.
L>Вчера наткнулся на это (вроде не баян). ППКС, так как я сам test infected. Программистам смотреть обязательно, вне зависимости от языка и платформы.
По нажатию на указанную ссылку скачался файл index.xul. И чито?
Здравствуйте, iHateLogins, Вы писали:
HL>Видно, что презу писал какой-то дебиловатый скрум-мастер или тренер, который сам код не трогал и не писал и не представляет себе, что применимость юнит-тестов сильно зависит от предметной области.
Применимость тестов вообще не зависит от предметной области. Сушествует очень мало, исчезающе мало случаев, где юнит-тесты, к сожалению, не применимы, но ERP-барахло к ним не относится. Туда в основном относится legacy код вроде драйверов очень низкого уровня, и то только та часть, которая непосредственно общается с железом. HL>Одно дело — реализация спеки какого-то стандарта, которая (реализация) будет черным ящиком. Пример — парсер XML, XSLT, регекспов. Реализаций куча — спека одна. Другое дело — это "бузинесс"-"методы" GetCustomerById, который состоит из вызова "select * from Customer where CustomerID = @id", в котором тестировать НЕЧЕГО. Ну т.е. конечно можно протестировать что он возвращает кастомеров с ID=3, ID=1, поддерживает отрицательные ID, в результате есть такие-то колонки итд. Но усилий по написанию и, главное, поддержке вы потратите гораздо больше, чем если просто откроете site.com/Customers/1 и убедитесь, что оно не валится. Ну или заскиптуете каким-нить веб-кликером за 5 секунд. Или просто Вася зайдёт на страничку и убедится, что не валится.
Ваш код не валится? Можете это доказать? А если на вход мусор подсунуть? Можете это доказать? А вспомните, что нужно вручную протестировать месяца через 2, когда GetCustomerId начнет выковыривать данные из другой таблицы? Точно уверены, что ничего другого не свалится?
Кстати, для веб-программирования тоже существуют тест-фреймворки.
HL>Короче, Шура, пишите, пишите тесты. Только потом не возмущайтесь, добавление колонки в базу стало СВЕРХ-СЛОЖНЫМ ИНЖЕНЕРНЫМ ПРОЕКТОМ.
Вы лично принимали участие в таких проектах?
Здравствуйте, landerhigh, Вы писали:
L>Потому что тема больно общая.
L>Вчера наткнулся на это (вроде не баян). ППКС, так как я сам test infected. Программистам смотреть обязательно, вне зависимости от языка и платформы.
Презентация замечательная, хоть и предназначена только для FireFox, а ведь некоторые "не смотрят FireFox уже три года".
Здравствуйте, AndrewVK, Вы писали:
AVK>А что там? ФФ нет и ставить никакого желания тоже.
Презентация. Юнит-тесты — это круто. Тестировать — это круто. Оттестируй и спи как ребенок.
Очень крупный шрифт, наверное, рассчитывалось на людей с нарушением зрения, странные картинки, некоторые предложения разделены на несколько слайдов — скорее всего, для того, чтобы вся аудитория могла читать хором, по слогам.
Под конец правда презентация сломалась — видимо, недостаточно хорошо тестировали.
Здравствуйте, iHateLogins, Вы писали:
HL>Одно дело — реализация спеки какого-то стандарта, которая (реализация) будет черным ящиком. Пример — парсер XML, XSLT, регекспов. Реализаций куча — спека одна. Другое дело — это "бузинесс"-"методы" GetCustomerById,
А чем вам GetCustomerById не чёрный ящик?
HL>который состоит из вызова "select * from Customer where CustomerID = @id"
Это оно сначала так выглядит... Потом начнётся: " WHERE Dropped = 0 AND Closed = 0 AND ЕЩЕ_КУЧА_НЕВЕДОМО_ОТКУДА_ВЗЯВШИХСЯ_ПРАВИЛ = 1"
А еще бы права ваши проверить не мешало бы: может ли текущий пользователь вообще видеть эти данные. А если может — то какие.
Это я так, сходу. Обычно всех правил и условий вагон с тележкой.
HL>в котором тестировать НЕЧЕГО.
HL>Но усилий по написанию и, главное, поддержке вы потратите гораздо больше, чем если просто откроете site.com/Customers/1 и убедитесь, что оно не валится. Ну или заскиптуете каким-нить веб-кликером за 5 секунд. Или просто Вася зайдёт на страничку и убедится, что не валится.
Угу. И бедный Вася будет заходить на эту страничку после каждого билда. Логинится под каждую из десятка ролей и заходить. Причём не только сюда, но еще и site.com/Supplier/1, site.com/Client/1, site.com/partner/1 и сколько там еще есть сущностей.
HL>Короче, Шура, пишите, пишите тесты. Только потом не возмущайтесь, добавление колонки в базу стало СВЕРХ-СЛОЖНЫМ ИНЖЕНЕРНЫМ ПРОЕКТОМ.
Дело в том, что пока я столкнусь(что вообще говоря не факт) с этой проблемой, у вас будут сидеть легионы красноглазых Вась, а вы будете отгребать за то, что выкатили новую падающую версию т.к. куда-то в дебри у Вась руки не дошли.
Здравствуйте, yoriсk.kiev.ua, Вы писали:
YKU>Это я так, сходу. Обычно всех правил и условий вагон с тележкой.
Поднимите руки те, у кого возникали хоть когда-нибудь проблемы с методом GetCustomerId.
Спасибо.
А теперь поднимите руки те, кому приходилось писать, а потом поддерживать кучу никому ненужных тестов, проверяющих работоспособность тривиальных методов.
Здравствуйте, iHateLogins, Вы писали:
HL>В том-то и дело, что проще всего поддерживаются приложения, которые ПРОЩЕ написаны! Не те, у которых есть 150 уровней абстракции, фабрики фабрик и которые расстрелены при помощи IoC, а которые сделаны ПРОСТО.
Просто — плохой термин. Хороший — понятно. Приложение должно быть написано понятно.
... << RSDN@Home 1.2.0 alpha 4 rev. 1227 on Windows Vista 6.1.7100.0>>
Здравствуйте, iHateLogins, Вы писали:
HL>Одно дело — реализация спеки какого-то стандарта, которая (реализация) будет черным ящиком. Пример — парсер XML, XSLT, регекспов. Реализаций куча — спека одна. Другое дело — это "бузинесс"-"методы" GetCustomerById, который состоит из вызова "select * from Customer where CustomerID = @id", в котором тестировать НЕЧЕГО. Ну т.е. конечно можно протестировать что он возвращает кастомеров с ID=3, ID=1, поддерживает отрицательные ID, в результате есть такие-то колонки итд. Но усилий по написанию и, главное, поддержке вы потратите гораздо больше, чем если просто откроете site.com/Customers/1 и убедитесь, что оно не валится. Ну или заскиптуете каким-нить веб-кликером за 5 секунд. Или просто Вася зайдёт на страничку и убедится, что не валится.
С другой стороны, вот представьте, окажется что GetCustomerById() — это у вас самая тормозная операция (в том смысле, что вся система тормозит именно об нее). Вам придет в голову светлая идея воткнуть в нее кеш на пару тысяч кастомеров, благо что память штука быстрая и дешевая. И станет ваш GetCustomerById() не простой функцией из трех строк, а довольно сложной штукой. Вот тут-то вам очень бы пригодился тест на него, а теста-то и нету.
Здравствуйте, yoriсk.kiev.ua, Вы писали:
HL>>который состоит из вызова "select * from Customer where CustomerID = @id"
YKU>Это оно сначала так выглядит... Потом начнётся: " WHERE Dropped = 0 AND Closed = 0 AND ЕЩЕ_КУЧА_НЕВЕДОМО_ОТКУДА_ВЗЯВШИХСЯ_ПРАВИЛ = 1"
Это еще ладно... Сценарий может быть куда тривиальнее:
1. В один прекрасный момент понадобится перевести прогу на СУБД, которая не понимает "@id" в качестве имени параметра и хочет вместо него "?" или ":id". Итог — проверяем тысячу подобных getCustomerById вручную, отмечая их в тетрадке галочками.
2. Один из программистов невнимательно просматривал diff перед тем как закоммитить свои изменения, и не заметил, что десять минут назад, поворачиваясь поглазеть на голые коленки секретарши, он случайно задел локтем клавиатуру. Итог — вышеприведенный запрос, который до этого нормально работал полгода, стал вот таким вот: "select * from Cust omer where CustomerID = @id". Т.к. полгода запрос честно отработал — никто про него даже не вспомнит, пока дело не дойдет до сдачи очередного этапа проекта и тотального ручного тестирования.
3. Тимлиду ударила в голову моча, и он решил, что во всех 258 таблицах базы primary key должен называться одинаково — например "Id". Порадовавшись, что прога еще не сдана заказчику, он за пару дней поправил скрипт создания базы, закоммитил его, и на следующее утро база автоматически пересоздалась на всех программерских машинах. Итог — тестировщики в ближайшие пару месяцев перевыполняют план по количеству отловленных косяков с SQL-запросами.
И так далее, и так далее — маленьких глупостей, которые могут привести к большим неприятностям, в любом крупном проекте обычно возникает вагон и маленькая тележка.
Здравствуйте, AndrewVK, Вы писали:
L>>Вы не знаете, что такое Юнит-тесты, для чего они нужны и как ими правильно пользоваться. AVK>Гы.
Человек, который говорит "тысячи никому не нужных тестов", не может знать, что такое юнит-тесты, не знает, для чего они нужны и как ими правильно пользоваться. Такое бывает, когда тесты пишут из-под палки по указявке сверху, да еще если смотрят покрытие.
Здравствуйте, yoriсk.kiev.ua, Вы писали:
YKU>А еще бы права ваши проверить не мешало бы: может ли текущий пользователь вообще видеть эти данные. А если может — то какие.
Кстати буквально на этой неделе мучался, написать тест на примитивную хранимую процедуру или не написать. Вроде ручками потестил все работает, можно и забить... В итоге тест написал. Локально (с локальным юзером) сработало, закоммитил, на бамбу (с реальными юзерами) — упало. Забыл пару грантов в DDL скриптах.
Здравствуйте, Eugeny__, Вы писали:
E__>Ей-богу, лучше бы выложили ppt.
Роман отчего минус-то?
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, Ушастый Ёж, Вы писали:
УЁ>Кстати буквально на этой неделе мучался, написать тест на примитивную хранимую процедуру или не написать. Вроде ручками потестил все работает, можно и забить... В итоге тест написал. Локально (с локальным юзером) сработало, закоммитил, на бамбу (с реальными юзерами) — упало. Забыл пару грантов в DDL скриптах.
If it isn't worth testing, it isn't worth writing.
Здравствуйте, neFormal, Вы писали:
F>вроде единственное упоминание get/set было о том, что не стоит их обкладывать тестами, чтобы повысить "покрытие кода тестами".. F>как то несерьёзно даже..
Опять чтение между строк?
Одна из основных причин негативного отношения к тестам состоит в том, что зачастую тесты насаждаются на проекте с уже имеющейся обширной базой кода в виде решения менеджмента "с сего дня мы пишем юнит тесты, покрытие кода к концу месяца должно быть не мнее 90%". Отсюда и "генерация" говнотестов для геттеров, которые и правда никому не нужны.
Тесты — это прежде всего инструмент разработчика. Если разработчик умеет его использовать, он нереально крут. Если не умеет, из-под палки его не заставить. Можно только увлечь за собой. Это и называется test infected.
Здравствуйте, Pzz, Вы писали:
Pzz>С другой стороны, вот представьте, окажется что GetCustomerById() — это у вас самая тормозная операция (в том смысле, что вся система тормозит именно об нее). Вам придет в голову светлая идея воткнуть в нее кеш на пару тысяч кастомеров, благо что память штука быстрая и дешевая. И станет ваш GetCustomerById() не простой функцией из трех строк, а довольно сложной штукой. Вот тут-то вам очень бы пригодился тест на него, а теста-то и нету.
Кто-то мешает после того, как GetCustomerId() стал сложной штукой написать на него тест?
И, кстати, далеко не факт, что этот тест должен быть юнит, возможно хватит и интеграционного.
Здравствуйте, AndrewVK, Вы писали:
HL>>В том-то и дело, что проще всего поддерживаются приложения, которые ПРОЩЕ написаны! Не те, у которых есть 150 уровней абстракции, фабрики фабрик и которые расстрелены при помощи IoC, а которые сделаны ПРОСТО.
AVK>Просто — плохой термин. Хороший — понятно. Приложение должно быть написано понятно.
Согласен. Есть куча приложений, в которых предметная область очень сложна и нетривиальна, конечно, реализовать их просто ну никак не получится. А вот реализовать их понятно, так, чтобы новый человек в команде не плевался и не продирался сквозь мегатонны макаронного кода — да, это можно.
Здравствуйте, landerhigh, Вы писали:
F>>вроде единственное упоминание get/set было о том, что не стоит их обкладывать тестами, чтобы повысить "покрытие кода тестами".. F>>как то несерьёзно даже.. L>Опять чтение между строк?
почему же?. почти цитата.. сам то смотрел презентацию?.
L>Одна из основных причин негативного отношения к тестам состоит в том, что зачастую тесты насаждаются на проекте с уже имеющейся обширной базой кода в виде решения менеджмента "с сего дня мы пишем юнит тесты,
вот в презентации я об этом не увидел.. можно цитату?.
L>покрытие кода к концу месяца должно быть не мнее 90%". Отсюда и "генерация" говнотестов для геттеров, которые и правда никому не нужны.
чтение между строк?.
L>Тесты — это прежде всего инструмент разработчика. Если разработчик умеет его использовать, он нереально крут.
скромнее надо быть.. самоубеждение — это, конечно, здорово, но выводы вызывают смех..
Здравствуйте, Пацак, Вы писали:
П>Здравствуйте, yoriсk.kiev.ua, Вы писали:
HL>>>который состоит из вызова "select * from Customer where CustomerID = @id"
YKU>>Это оно сначала так выглядит... Потом начнётся: " WHERE Dropped = 0 AND Closed = 0 AND ЕЩЕ_КУЧА_НЕВЕДОМО_ОТКУДА_ВЗЯВШИХСЯ_ПРАВИЛ = 1"
П>Это еще ладно... Сценарий может быть куда тривиальнее: П>1. В один прекрасный момент понадобится перевести прогу на СУБД, которая не понимает "@id" в качестве имени параметра и хочет вместо него "?" или ":id". Итог — проверяем тысячу подобных getCustomerById вручную, отмечая их в тетрадке галочками.
Ну мы же взрослые люди и знаем, что вероятность того, что прогу будут переводить с одной СУБД на другую — крайне низка, а даже если и будут, но параллельно с полным rearchitecture и изменением функционала. Юнит-тесты опять и здесь не помогут.
П>2. Один из программистов невнимательно просматривал diff перед тем как закоммитить свои изменения, и не заметил, что десять минут назад, поворачиваясь поглазеть на голые коленки секретарши, он случайно задел локтем клавиатуру. Итог — вышеприведенный запрос, который до этого нормально работал полгода, стал вот таким вот: "select * from Cust omer where CustomerID = @id". Т.к. полгода запрос честно отработал — никто про него даже не вспомнит, пока дело не дойдет до сдачи очередного этапа проекта и тотального ручного тестирования.
Какие-то клинические идиотические случаи. Во-первых, если разработчик случайно чекинит говно-код, то гнать его взашей и без всяких юнит-тестов. Во-вторых, code review никто не отменял. А-втретьих, случайно изменить код, зачекинить и не побить билд — это, право, надо уметь
П>3. [b]Тимлиду ударила в голову моча, и он решил, что во всех 258 таблицах базы primary key должен называться одинаково — например "Id". Порадовавшись, что прога еще не сдана заказчику, он за пару дней поправил скрипт создания базы, закоммитил его, и на следующее утро база автоматически пересоздалась на всех программерских машинах. Итог — тестировщики в ближайшие пару месяцев перевыполняют план по количеству отловленных косяков с SQL-запросами.
Чувак, ты просто жжёшь! То тимлиду ударила моча, то программист засмотрелся на коленки, еще что? Метеорит удаил по серверу и + заменился на -, оставив билд рабочим? Да так, что никто и не заметил изменений.
П>И так далее, и так далее — маленьких глупостей, которые могут привести к большим неприятностям, в любом крупном проекте обычно возникает вагон и маленькая тележка.
Неприятности возникают, безусловно, но, во-первых, компилятор что-то ловит, функц. тесты ОЧЕНЬ много что ловят и, конечно, глаза тестера и разработчика тоже ловят.
Что касается юнит-тестов, то от них в реальных приложений столько ложных срабатываний, что либо на них тратят 80% времени, либо просто в определённый момент проблему "лечат" удалением юнит-тестов из тест-листа
Здравствуйте, Eugeny__, Вы писали:
К>>>Ни IE7, ни Safari4 не смогли открыть эту ботву — там mime-тип не указан, а xml по-человечески не рендерится. L>>Это, мопед не мой. L>>Похоже, это какой-то доморощеный транслятор ppt->html
E__>Ей-богу, лучше бы выложили ppt.
"Религия" им не позволяет. Пусть народ давится говно-презой с тремя красными буквами на слайде, зато не пользуется "диаволскым" Мелкософтом
L>>Поднимите руки те, кому не приходится отлаживать свой собственный код в отладчике. L>Юнит-тестирование избавляет от отладчика?
Практически полностью. L>А в самих тестах ошибки исключены? Orly?
Практичски полностью.
Я правильно понимаю, что все собравшиеся здесь профессионалы не видят ничего ненормального в том, что только что написанный код нужно ковырять отладчиком?
Здравствуйте, neFormal, Вы писали:
F> скромнее надо быть.. самоубеждение — это, конечно, здорово, но выводы вызывают смех..
А ты смейся, смейся. Смех полезен.
Здравствуйте, landerhigh, Вы писали:
F>> скромнее надо быть.. самоубеждение — это, конечно, здорово, но выводы вызывают смех.. L>А ты смейся, смейся. Смех полезен.
Здравствуйте, iHateLogins, Вы писали:
HL>Согласен. Есть куча приложений, в которых предметная область очень сложна и нетривиальна, конечно, реализовать их просто ну никак не получится.
Да нет, дело не только в этом. Простота не должна быть в ущерб понятности. К примеру, linq запрос сложнее рукопашных циклов, но, обычно, значительно понятнее.
... << RSDN@Home 1.2.0 alpha 4 rev. 1227 on Windows Vista 6.1.7100.0>>
Здравствуйте, AndrewVK, Вы писали:
HL>>Согласен. Есть куча приложений, в которых предметная область очень сложна и нетривиальна, конечно, реализовать их просто ну никак не получится. AVK>Да нет, дело не только в этом. Простота не должна быть в ущерб понятности. К примеру, linq запрос сложнее рукопашных циклов, но, обычно, значительно понятнее.
Эх, Linq, linq... как посмотришь на те запросы, которые он генерит (linq2sql), становится грустно. Да и подкрутить мало что можно — т.е. имеем очередной показательный пример Leaky Abstraction.
Здравствуйте, landerhigh, Вы писали:
L>Я правильно понимаю, что все собравшиеся здесь профессионалы не видят ничего ненормального в том, что только что написанный код нужно ковырять отладчиком?
Из собравшихся здесь профессионалов только один считает, что если не написать горы юнит-тестов, то непременно "только что написанный код нужно ковырять отладчиком". С какой целью, позвольте спросить?
Правда не совсем понятно вот что.
L>>А в самих тестах ошибки исключены? Orly? L>Практичски полностью.
Раз уж вы можете писать тесты без ошибок, стало быть можете и любой другой код писать без ошибок. А раз так, накой вам юнит-тесты?
Здравствуйте, Laurel, Вы писали:
L>Раз уж вы можете писать тесты без ошибок, стало быть можете и любой другой код писать без ошибок. А раз так, накой вам юнит-тесты?
только с тестами становишься нереально крутым.. (с)
Здравствуйте, landerhigh, Вы писали:
L>Потому что тема больно общая.
L>Вчера наткнулся на это (вроде не баян). ППКС, так как я сам test infected. Программистам смотреть обязательно, вне зависимости от языка и платформы.
хня какая-то
если там и есть полезное содержание, то за формой я его не уловил
Здравствуйте, landerhigh, Вы писали:
HL>>Также бесполезно спорить с людьми, которые вместо того, чтобы копать (заметьте — не решать дифуры, не искать нефть, а именно копать) начинают "тестировать лопату" каждые 15 минут, проверять схемы экскаватора, цементируют яму бетоном (для надёжности), хотя знают, что завтра бетон придётся вытаскивать обратно. L>Вы не знаете, что такое Юнит-тесты, для чего они нужны и как ими правильно пользоваться. Это случается, когда тестирование на проекте внедряется указанием сверху.
Для танкистов: в самих юнит-тестах проблем нет, проблема в том, что ими неумело пользуются, цементируя код и лишая себя возможности что-либо переделать (т.к. дорого, заказчик не одобрит)
HL>>вместо простых селектов в базе накручиваются просто МЕГАТОННЫ всякого водопроводного (plumbing) говно-кода, фреймворки над фреймворками... а дальше начинается... добавить колонку? СЛОЖНЕЙШАЯ ЗАДАЧА! Переработать модуль? Да проще новый написать, желательно даже не модуль, а проект с нуля, потому что разобраться в тоннах запутанного кода с десятками тысяч никому не нужных юнит-тестов становится просто невозможно. L>Замечательно. Отличный пример разработки класса "надо копать".
Ну так все копают-то, нетленку вояют единицы... В ERP и сайтостроении работает подавляющее большинство разработчиков, мало кто пишет математические алгоритмы или архиваторы (где, юнит-тесты просто АРХИ-НУЖНЫ!).
Здравствуйте, landerhigh, Вы писали:
E__>>Нету лисы, вырвал с корнями из системы. E__>>Есть в более фф-независимом формате? L>Звиняйте, все, что нашел.
Здравствуйте, x64, Вы писали:
BIS>>Они бы ещё в этой презентации каждую букву на отдельный слайд вынесли
x64>Угу, запарился тыкать...
я сдался где-то на 15-20 странице.
Здравствуйте, iHateLogins, Вы писали:
E__>>Ей-богу, лучше бы выложили ppt.
HL>"Религия" им не позволяет. Пусть народ давится говно-презой с тремя красными буквами на слайде, зато не пользуется "диаволскым" Мелкософтом
Да при чем тут это. Я бы ppt замечательно открыл опенофисом — сижу под убунтой.
А вот ставить браузер ради просмотра одной презентации я не буду, идут они лесом.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, neFormal, Вы писали:
F>Здравствуйте, landerhigh, Вы писали:
L>>Программистам смотреть обязательно, вне зависимости от языка и платформы.
F>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О.
Одним надо доказывать полезность тестов, другим полезнгость ФП, третьим полезность ООП, а четвертым вообзе полезность программирования
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, AndrewVK, Вы писали:
HL>>>Согласен. Есть куча приложений, в которых предметная область очень сложна и нетривиальна, конечно, реализовать их просто ну никак не получится. AVK>>Да нет, дело не только в этом. Простота не должна быть в ущерб понятности. К примеру, linq запрос сложнее рукопашных циклов, но, обычно, значительно понятнее.
HL>Эх, Linq, linq... как посмотришь на те запросы, которые он генерит (linq2sql), становится грустно. Да и подкрутить мало что можно — т.е. имеем очередной показательный пример Leaky Abstraction.
А работают они очень даже прилично.
Кроме этого ты бы руками в жизни не написал sql, который генерит Linq2sql из более-менее сложного linq запроса.
Здравствуйте, iHateLogins, Вы писали:
HL>Ну мы же взрослые люди и знаем, что вероятность того, что прогу будут переводить с одной СУБД на другую — крайне низка
Мы взрослые люди, но вроде пока не старые. Тем не менее я за свою карьеру застал уже две таких проги.
HL>а даже если и будут, но параллельно с полным rearchitecture и изменением функционала.
Зафига это кому надо, если предыдущий функционал всех устраивал?
HL>Юнит-тесты опять и здесь не помогут.
Очень даже помогут — как сигнал, что не затронутые rearchitecture модули продолжают/перестали нормально работать.
HL>Какие-то клинические идиотические случаи. Во-первых, если разработчик случайно чекинит говно-код, то гнать его взашей и без всяких юнит-тестов.
No comments. Кто ни разу в жизни не коммитил код с ошибками — пусть первый бросит в меня камень.
HL>Во-вторых, code review никто не отменял.
Ага, в теории. На практике же оно применяется еще реже, чем написание тестов. Потому что "...а фигле показывать кому-то метод getCustomerById — в нем же в принципе невозможно ошибиться, тем более такому крутому перцу, как я!".
HL>в третьих, случайно изменить код, зачекинить и не побить билд — это, право, надо уметь
Тезис из разряда "этого не может быть потому что не может быть никогда" (с)
HL> Чувак, ты просто жжёшь!
По сути есть что сказать или как обычно?
HL>Неприятности возникают, безусловно, но, во-первых, компилятор что-то ловит, функц. тесты ОЧЕНЬ много что ловят и, конечно, глаза тестера и разработчика тоже ловят.
Ага, только пользуясь твоей логикой — функциональными тестами тестить тоже не надо: ведь "компилятор что-то ловит, а остальное студенты руками выгребут" и "ошибки там быть не может, потому что не может быть никогда". Ну и заодно — потому что "от функциональных тестов столько ложных срабатываний".
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, iHateLogins, Вы писали:
HL>>Юнит-тесты уже становятся параноей, в 99% они превращаются в тестирование сеттеров и геттеров и код типа Assert.AreEqual(2+2, 4). L>Не читал, но осуждаю, да?
L>Если Вы не умеете их готовить, то это вовсе не значит, что все не умеют.
ППКС, так как я сам test infected.
Ваше? А презентацию то читали?
Вот на слайдах 180-186 там и говорится, что каждый тест должен тестировать один метод и один класс. Если не дай бог у нас задействовано два класса — то это уже никакой не юнит-тест, а интегрейшн-тест. Поэтому надо второй класс обязательно заменить моком. А то ведь из-за бага в классе А могут заподозрить невинновный класс B.
Здравствуйте, neFormal, Вы писали:
F>Здравствуйте, landerhigh, Вы писали:
L>>Программистам смотреть обязательно, вне зависимости от языка и платформы.
F>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О.
С идеей тестирования то все в порядке. С идеей автоматизированного тестирования тоже вроде никто не спорит.
Проблема в том что на здравые идеи понавешали шаманских ритуалов "дизайн должен определяться тестами", "один тест — один класс", "паттерны зеленой полосы" и т.д.
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, neFormal, Вы писали:
F>>Здравствуйте, landerhigh, Вы писали:
L>>>Программистам смотреть обязательно, вне зависимости от языка и платформы.
F>>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О.
G>Одним надо доказывать полезность тестов, другим полезнгость ФП, третьим полезность ООП, а четвертым вообзе полезность программирования
Если вы не можете кратко обосновать полезность этих вещей, значит вы их плохо понимаете сами.
Здравствуйте, Константин Б., Вы писали:
КБ>Вот на слайдах 180-186 там и говорится
186??? я рад что у меня не установлен ФФ.
КБ>что каждый тест должен тестировать один метод и один класс.
В общем верно, за исключением замечания ниже.
КБ>Если не дай бог у нас задействовано два класса — то это уже никакой не юнит-тест, а интегрейшн-тест. Поэтому надо второй класс обязательно заменить моком. А то ведь из-за бага в классе А могут заподозрить невинновный класс B.
Тут понятие класса всеобъемлющее получается. Классмами могут выражаться компоненты, сервисы, данные и их коллекции, хелперы.
например если у вас метод испльзует класс очереди, то не надо заменять очередь на мок очереди.
А вот если тестируемый класс является компонентом\сервисом BL, например начисляет ЗП сотрудникам, и он обращается к компоненту, который достает данные из хранилща, то в тесте этот компонент заменить моком.
КБ>Как еще такой подход назвать как не параноей?
Здравым смыслом.
Напимер есть компонент A, который зависит от компонента B.
У A есть N сценариев работы, у B есть M сценариев работы. Чтобы протестировать свзяку A+B во всех сценариях потребуется написать N*M тестов, или чуть меньше если если некоторые сценарии для совокупности компонентов взаимоисключающие.
Если на время тестирования A заменить B моком, то потребуется написать N тестов для A, а потом M тестов для B, тобы проверить что B работает правильно. В итоге получаем N+M тестов.
на самом деле люди пишут гораздо меньше, чем N+M, и уж тем более никто не осилит N*M, поэтому пишут интеграционные тесты примерно для 20% сценариев совместной работы A и B, чтобы покрыть 80% реальных сценариев использования.
Здравствуйте, Константин Б., Вы писали:
КБ>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, neFormal, Вы писали:
F>>>Здравствуйте, landerhigh, Вы писали:
L>>>>Программистам смотреть обязательно, вне зависимости от языка и платформы.
F>>>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О.
G>>Одним надо доказывать полезность тестов, другим полезнгость ФП, третьим полезность ООП, а четвертым вообзе полезность программирования
КБ>Если вы не можете кратко обосновать полезность этих вещей, значит вы их плохо понимаете сами.
Объяснить то всегда можно, но не факт что человек поймет. Особенно если он имеет негативный опыт использования.
Здравствуйте, iHateLogins, Вы писали:
HL>Одно дело — реализация спеки какого-то стандарта, которая (реализация) будет черным ящиком. Пример — парсер XML, XSLT, регекспов. Реализаций куча — спека одна. Другое дело — это "бузинесс"-"методы" GetCustomerById, который состоит из вызова "select * from Customer where CustomerID = @id", в котором тестировать НЕЧЕГО.
Навскидку три проблемы тут точно можно протестировать:
1) таймаут при блокировке этой записи и истечении времени ожидания снятия блокировки
2) deadlock
3) отсутствие прав
это навскидку. Если это не select, а update то добавляются еще:
4) каскадное обновление каких-либо других объектов
5) соответствие переданных данных constraintам БД
6) отсутствие/наличие исключений при работе триггеров
7) скорость поиска и изменения в VLDB-среде и опять же таймаут.
8) соответствие типов переданных данных типам полей в БД.
Это если не особо думать, можно еще нарисовать столько же нюансов.
Здравствуйте, Константин Б., Вы писали:
КБ>Проблема в том что на здравые идеи понавешали шаманских ритуалов "дизайн должен определяться тестами", "один тест — один класс", "паттерны зеленой полосы" и т.д.
Веришь, нет — но ты первый, от кого я услышал про эти ритуалы. Где ты их взял вообще?
КБ>"дизайн должен определяться тестами"
Не дизайн, а интерфейс модуля. И не "должен", а "может, когда это удобно". А вот то, что оно удобно в очень большом проценте случаев — это да, чистая правда.
КБ>"один тест — один класс"
Кто-то кому-то запрещает писать несколько тестов на один класс?
КБ>"паттерны зеленой полосы"
Паттерны в принципе не могут вызывать шаманских ритуалов — попросту потому, что применяются они только в удобных для этого случаях и в результате осознанного решения. Собственно для того и придумана такая вещь, как паттерн.
Здравствуйте, AndrewVK, Вы писали:
AVK>Человек, который переходит на личности, не может аргументировать свою позицию, скорее всего потому что таких аргументов у него нет.
Очень интересно получается.
Добрая половина ответов в теме — переход на личности без аргументов. Например, заявление, что не смотрели потомушта в их единственном и неповторимо браузере не открылось. Ну, спорить не буду, хотели бы посмотреть, посмотрели бы. Но дальше начались наезды от презентацию не смотревших, но мнение имеющих. Доводы о том, что оригинальная презентация как раз объясняет те мифы, о которых они говорят, пропускались мимо ушей.
Основной довод, как я понял — "не хочу поддерживать кучи никому не нужных тестов". Комментировать его я не собираюсь. Если тесты "никому не нужные", аффтар просто не понимает предназначения тестов.
Вообще, я давно отмечал, что тесты используются во всех отраслях промышленности. Вот, Аирбас строит самолет. И нужны им гидравлические цилиндры определенных параметров. Думаю, совершенно очевидно, что цилиндры эти пройдут полных цикл испытаний прежде чем будет заключен договор на поставку и потом дефектоскопия каждого из них будет проводиться до установки на самолет?
Как думаешь, через сколько минут инженер, который заявит, что, дескать, некогда эту деталюшку проверять на соответсвие параметрам, бо самолет собирать надо, будт собирать свои вещички?
Тестирование есть везде. Дефектоскопия, поверки и так далее. Что дает вам право думать, что разработка программного обеспечения чем-то отличается? Программа собирается из кирпичиков (если у Вас не так, извините, мне будет очень трудно с Вами дальше говорить). Проверить каждый кирпичик на соотвествие ожидаемого от него поведения очень просто. Искать косяк в уже построенной системе очень и очень сложно.
У меня на днях было очередное подтверждение тупиковости подхода. Рисовали три очень опытных программиста библиотеку одну. Так как альфу сделать нужно было очень-очень быстро, они решили, что "тестировать некогда, копать надо". Копали. Код красивый, правильных, соответствует правилам оформления, кругом ООП и паттерны. Копали месяц, заставляли это работать два месяца. То то не так работает, то здесь не то получается, то вот тут память утекла, то здесь ежа с ужом скрестить не получается. Альфа вышла с задержкой в полтора месяца. То самое правило — 20% разработка, 80% — annoying crap.
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Константин Б., Вы писали:
КБ>>Вот на слайдах 180-186 там и говорится G>186??? я рад что у меня не установлен ФФ.
КБ>>что каждый тест должен тестировать один метод и один класс. G>В общем верно, за исключением замечания ниже.
КБ>>Если не дай бог у нас задействовано два класса — то это уже никакой не юнит-тест, а интегрейшн-тест. Поэтому надо второй класс обязательно заменить моком. А то ведь из-за бага в классе А могут заподозрить невинновный класс B. G>Тут понятие класса всеобъемлющее получается. Классмами могут выражаться компоненты, сервисы, данные и их коллекции, хелперы. G>например если у вас метод испльзует класс очереди, то не надо заменять очередь на мок очереди. G>А вот если тестируемый класс является компонентом\сервисом BL, например начисляет ЗП сотрудникам, и он обращается к компоненту, который достает данные из хранилща, то в тесте этот компонент заменить моком.
В том что моки полезны иногда никто не сомневается. В презентации четко сказано "один тест — один класс".
КБ>>Как еще такой подход назвать как не параноей? G>Здравым смыслом.
Нет. Здравый смысл — это когда пишем столько тестов сколько целесообразно и тех тестов что целесообразно, до кода или после (смотря что целесообразнее). А если следуем всяким глупым правилам — то это никак не здравый смысл.
G>Напимер есть компонент A, который зависит от компонента B. G>У A есть N сценариев работы, у B есть M сценариев работы. Чтобы протестировать свзяку A+B во всех сценариях потребуется написать N*M тестов, или чуть меньше если если некоторые сценарии для совокупности компонентов взаимоисключающие. G>Если на время тестирования A заменить B моком, то потребуется написать N тестов для A, а потом M тестов для B, тобы проверить что B работает правильно. В итоге получаем N+M тестов.
Если только не окажется что A использует B только в K режимах и N*K << N+M. Тогда смысла в юнит-тестах для B нет вообще.
G>на самом деле люди пишут гораздо меньше, чем N+M, и уж тем более никто не осилит N*M, поэтому пишут интеграционные тесты примерно для 20% сценариев совместной работы A и B, чтобы покрыть 80% реальных сценариев использования.
Вот именно. На самом деле люди пишут не так как оно описывается в презентациях, статьях и книжках, а так как надо в их конкретном случае.
F>>>>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О. G>>>Одним надо доказывать полезность тестов, другим полезнгость ФП, третьим полезность ООП, а четвертым вообзе полезность программирования КБ>>Если вы не можете кратко обосновать полезность этих вещей, значит вы их плохо понимаете сами. G>Объяснить то всегда можно, но не факт что человек поймет. Особенно если он имеет негативный опыт использования.
Вы вероятно путаете "поймет" и "поверит". Если обоснование заключается в "практика показывает что X — полезно" или "достоинства X, перевешивают недостатки", то свой опыт он естественно ближе к телу.
Здравствуйте, Пацак, Вы писали:
П>Здравствуйте, Константин Б., Вы писали:
КБ>>Проблема в том что на здравые идеи понавешали шаманских ритуалов "дизайн должен определяться тестами", "один тест — один класс", "паттерны зеленой полосы" и т.д. П>Веришь, нет — но ты первый, от кого я услышал про эти ритуалы. Где ты их взял вообще?
Ну например презентация приведенная топикстартером. Или там книги товарищей Бека и Фаулера.
КБ>>"дизайн должен определяться тестами" П>Не дизайн, а интерфейс модуля. И не "должен", а "может, когда это удобно". А вот то, что оно удобно в очень большом проценте случаев — это да, чистая правда.
Для меня фраза "интерфейс определяется тестами" — бессмыслица. Если функциональные тесты еще хоть как-то можно вывести из функциональных требований, то юнит-тесты проектируются "из головы", а то и подгоняются под уже придуманный интерфейс.
КБ>>"один тест — один класс" П>Кто-то кому-то запрещает писать несколько тестов на один класс?
Нет. Но презентация запрещает писать один тест на несколько классов.
КБ>>"паттерны зеленой полосы" П>Паттерны в принципе не могут вызывать шаманских ритуалов — попросту потому, что применяются они только в удобных для этого случаях и в результате осознанного решения. Собственно для того и придумана такая вещь, как паттерн.
Здравствуйте, Константин Б., Вы писали:
КБ>В том что моки полезны иногда никто не сомневается. В презентации четко сказано "один тест — один класс".
Это слишком сильное утверждение, из-за рамытости понятия "класс". В языках, где ООП — центральная парадигма, классом может быть что угодно, в том числе и числа.
В таком контексте "один тест — один класс" — абсурд.
Надо понимать что когда написано "один тест — один класс", то дадеко не каждый класс имеется ввиду.
КБ>>>Как еще такой подход назвать как не параноей? G>>Здравым смыслом.
КБ>Нет. Здравый смысл — это когда пишем столько тестов сколько целесообразно и тех тестов что целесообразно, до кода или после (смотря что целесообразнее). А если следуем всяким глупым правилам — то это никак не здравый смысл.
Перед тем как правилам следовать их стоит понять. Слепое следование чему-либо приводит к негативным эффектам.
G>>Напимер есть компонент A, который зависит от компонента B. G>>У A есть N сценариев работы, у B есть M сценариев работы. Чтобы протестировать свзяку A+B во всех сценариях потребуется написать N*M тестов, или чуть меньше если если некоторые сценарии для совокупности компонентов взаимоисключающие. G>>Если на время тестирования A заменить B моком, то потребуется написать N тестов для A, а потом M тестов для B, тобы проверить что B работает правильно. В итоге получаем N+M тестов.
КБ>Если только не окажется что A использует B только в K режимах и N*K << N+M. Тогда смысла в юнит-тестах для B нет вообще.
Неверно. Класс B может использоваться не только A, но еще и классами C, D, E (соотвественно N1, N2, N3 сценариев работы), и каждый из них использует B только в K режимах.
тогда общее число интеграционных тестов будет K*(N+N1+N2+N3), что больше чем M+N+N1+N2+N3 даже при небольших K и N.
Например N=N1=N2=N3=3. M = 10, K = 2 тогда интеграционных тестов надо 2*(3+3+3+3) = 24, а unit-тестов 22. Причем unit-тесты будут проще интеграционных.
А если рассмотреть не два компонента, а три X->A->B, то получается экспоненциальный рост количества интеграционных тестов и линейный при использовании unit-тестирования.
G>>на самом деле люди пишут гораздо меньше, чем N+M, и уж тем более никто не осилит N*M, поэтому пишут интеграционные тесты примерно для 20% сценариев совместной работы A и B, чтобы покрыть 80% реальных сценариев использования.
КБ>Вот именно. На самом деле люди пишут не так как оно описывается в презентациях, статьях и книжках, а так как надо в их конкретном случае.
Далеко не все знают как надо.
Здравствуйте, Константин Б., Вы писали:
КБ>Здравствуйте, gandjustas, Вы писали:
F>>>>>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О. G>>>>Одним надо доказывать полезность тестов, другим полезнгость ФП, третьим полезность ООП, а четвертым вообзе полезность программирования КБ>>>Если вы не можете кратко обосновать полезность этих вещей, значит вы их плохо понимаете сами. G>>Объяснить то всегда можно, но не факт что человек поймет. Особенно если он имеет негативный опыт использования.
КБ>Вы вероятно путаете "поймет" и "поверит".
Это одно и тоже в данном контексте.
КБ>Если обоснование заключается в "практика показывает что X — полезно" или "достоинства X, перевешивают недостатки", то свой опыт он естественно ближе к телу.
Ну если человек верит в свой опыт как в абсолютную истину, то да.
Здравствуйте, Константин Б., Вы писали:
КБ>>>"дизайн должен определяться тестами" П>>Не дизайн, а интерфейс модуля. И не "должен", а "может, когда это удобно". А вот то, что оно удобно в очень большом проценте случаев — это да, чистая правда. КБ>Для меня фраза "интерфейс определяется тестами" — бессмыслица. Если функциональные тесты еще хоть как-то можно вывести из функциональных требований, то юнит-тесты проектируются "из головы", а то и подгоняются под уже придуманный интерфейс.
На самом деле чтобы написать тест надо знать как выглядит интерфейс тестируемого модуля. Поэтому тесты не могут определять интерфейс.
КБ>>>"паттерны зеленой полосы" П>>Паттерны в принципе не могут вызывать шаманских ритуалов — попросту потому, что применяются они только в удобных для этого случаях и в результате осознанного решения. Собственно для того и придумана такая вещь, как паттерн. КБ>Если бы все было так идеально...
Это просто неуместное применение слова "паттерн".
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Константин Б., Вы писали:
КБ>>В том что моки полезны иногда никто не сомневается. В презентации четко сказано "один тест — один класс". G>Это слишком сильное утверждение, из-за рамытости понятия "класс". В языках, где ООП — центральная парадигма, классом может быть что угодно, в том числе и числа. G>В таком контексте "один тест — один класс" — абсурд. G>Надо понимать что когда написано "один тест — один класс", то дадеко не каждый класс имеется ввиду.
Ну вообще-то неплохо бы об этом сказать, прежде чем ожидать понимания.
КБ>>>>Как еще такой подход назвать как не параноей? G>>>Здравым смыслом. КБ>>Нет. Здравый смысл — это когда пишем столько тестов сколько целесообразно и тех тестов что целесообразно, до кода или после (смотря что целесообразнее). А если следуем всяким глупым правилам — то это никак не здравый смысл. G>Перед тем как правилам следовать их стоит понять. Слепое следование чему-либо приводит к негативным эффектам.
Может тогда ну их нафиг эти правила, а?
КБ>>Если только не окажется что A использует B только в K режимах и N*K << N+M. Тогда смысла в юнит-тестах для B нет вообще. G>Неверно. Класс B может использоваться не только A, но еще и классами C, D, E (соотвественно N1, N2, N3 сценариев работы), и каждый из них использует B только в K режимах. G>тогда общее число интеграционных тестов будет K*(N+N1+N2+N3), что больше чем M+N+N1+N2+N3 даже при небольших K и N. G>Например N=N1=N2=N3=3. M = 10, K = 2 тогда интеграционных тестов надо 2*(3+3+3+3) = 24, а unit-тестов 22. Причем unit-тесты будут проще интеграционных. G>А если рассмотреть не два компонента, а три X->A->B, то получается экспоненциальный рост количества интеграционных тестов и линейный при использовании unit-тестирования.
Только правильность классов по отедельности не гарантирует правильности их совместной работы. А если гарантирует, то тем более никакого смысла каждую комбинацию тестировать нет. И кол-во тестов сокращается до max(M,N).
G>>>на самом деле люди пишут гораздо меньше, чем N+M, и уж тем более никто не осилит N*M, поэтому пишут интеграционные тесты примерно для 20% сценариев совместной работы A и B, чтобы покрыть 80% реальных сценариев использования.
КБ>>Вот именно. На самом деле люди пишут не так как оно описывается в презентациях, статьях и книжках, а так как надо в их конкретном случае. G>Далеко не все знают как надо.
Ага. Но вместо того чтобы это объяснить, придумываются глупые правила.
Здравствуйте, gandjustas, Вы писали:
F>>>>>>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О. G>>>>>Одним надо доказывать полезность тестов, другим полезнгость ФП, третьим полезность ООП, а четвертым вообзе полезность программирования КБ>>>>Если вы не можете кратко обосновать полезность этих вещей, значит вы их плохо понимаете сами. G>>>Объяснить то всегда можно, но не факт что человек поймет. Особенно если он имеет негативный опыт использования.
КБ>>Вы вероятно путаете "поймет" и "поверит". G>Это одно и тоже в данном контексте.
Нет. Доказательство есть доказательство, а апеляция к своему опыту — не доказательство.
КБ>>Если обоснование заключается в "практика показывает что X — полезно" или "достоинства X, перевешивают недостатки", то свой опыт он естественно ближе к телу. G>Ну если человек верит в свой опыт как в абсолютную истину, то да.
Только ни о каком доказательстве полезности здесь речь не идет.
Здравствуйте, Константин Б., Вы писали:
КБ>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, Константин Б., Вы писали:
КБ>>>В том что моки полезны иногда никто не сомневается. В презентации четко сказано "один тест — один класс". G>>Это слишком сильное утверждение, из-за рамытости понятия "класс". В языках, где ООП — центральная парадигма, классом может быть что угодно, в том числе и числа. G>>В таком контексте "один тест — один класс" — абсурд. G>>Надо понимать что когда написано "один тест — один класс", то дадеко не каждый класс имеется ввиду.
КБ>Ну вообще-то неплохо бы об этом сказать, прежде чем ожидать понимания.
Это сложно. Я, например, сходу не могу сказать чем отличается класс вообще, от того класса который имеется ввиду в этой фразе.
КБ>>>>>Как еще такой подход назвать как не параноей? G>>>>Здравым смыслом. КБ>>>Нет. Здравый смысл — это когда пишем столько тестов сколько целесообразно и тех тестов что целесообразно, до кода или после (смотря что целесообразнее). А если следуем всяким глупым правилам — то это никак не здравый смысл. G>>Перед тем как правилам следовать их стоит понять. Слепое следование чему-либо приводит к негативным эффектам.
КБ>Может тогда ну их нафиг эти правила, а?
Нет, нафиг такой подход, когда читаешь кучу таких "правил", а потом слемо им следуешь.
Это называется культ карго
КБ>>>Если только не окажется что A использует B только в K режимах и N*K << N+M. Тогда смысла в юнит-тестах для B нет вообще. G>>Неверно. Класс B может использоваться не только A, но еще и классами C, D, E (соотвественно N1, N2, N3 сценариев работы), и каждый из них использует B только в K режимах. G>>тогда общее число интеграционных тестов будет K*(N+N1+N2+N3), что больше чем M+N+N1+N2+N3 даже при небольших K и N. G>>Например N=N1=N2=N3=3. M = 10, K = 2 тогда интеграционных тестов надо 2*(3+3+3+3) = 24, а unit-тестов 22. Причем unit-тесты будут проще интеграционных. G>>А если рассмотреть не два компонента, а три X->A->B, то получается экспоненциальный рост количества интеграционных тестов и линейный при использовании unit-тестирования.
КБ>Только правильность классов по отедельности не гарантирует правильности их совместной работы. А если гарантирует, то тем более никакого смысла каждую комбинацию тестировать нет. И кол-во тестов сокращается до max(M,N).
Почему же? Если A — работает правльно во всех сценариях и правильно вызывает в этих сценариях B и в тоже время B работает правильно во всех сценариях, то и их совокупность будет работать правильно. Это в теории.
На практике человек не может обычно написать тесты для всех сценариев A и B, может получиться так что A использует B таким образом, что B в таком сценарии не тестировался.
КБ>>>Вот именно. На самом деле люди пишут не так как оно описывается в презентациях, статьях и книжках, а так как надо в их конкретном случае. G>>Далеко не все знают как надо.
КБ>Ага. Но вместо того чтобы это объяснить, придумываются глупые правила.
Сложно объяснять как правильно писать тесты, это также сложно как правильно писать код.
Можно долго рассказывать о том как не написать плохой код, но следование всем этим правилам не гарантирует что код получится хорошим.
С тестами аналогично. Можно исключить все антипаттерны в своих тестах, но не факт что тесты получатся хорошие.
Я уже писал что самый лучший способ изучать TDD — смотреть видеозаписи о том как люди пишут код по TDD.
Здравствуйте, gandjustas, Вы писали:
G>>>В таком контексте "один тест — один класс" — абсурд. G>>>Надо понимать что когда написано "один тест — один класс", то дадеко не каждый класс имеется ввиду.
КБ>>Ну вообще-то неплохо бы об этом сказать, прежде чем ожидать понимания.
G>Это сложно. Я, например, сходу не могу сказать чем отличается класс вообще, от того класса который имеется ввиду в этой фразе.
Ну и ладно. Можно же просто рассказать о моках, о их пользе. А само применение моков оставить на усмотрение разработчика.
КБ>>Может тогда ну их нафиг эти правила, а? G>Нет, нафиг такой подход, когда читаешь кучу таких "правил", а потом слемо им следуешь. G>Это называется культ карго
А нафига правила если им нельзя следовать?
G>На практике человек не может обычно написать тесты для всех сценариев A и B, может получиться так что A использует B таким образом, что B в таком сценарии не тестировался.
Ага. Поэтому интеграционные тесты — рулят
КБ>>>>Вот именно. На самом деле люди пишут не так как оно описывается в презентациях, статьях и книжках, а так как надо в их конкретном случае. G>>>Далеко не все знают как надо.
КБ>>Ага. Но вместо того чтобы это объяснить, придумываются глупые правила. G>Сложно объяснять как правильно писать тесты, это также сложно как правильно писать код.
Тесты надо писать так:
1. Чтобы они запускались автоматически
2. Чтобы тестировали то что нужно.
А будут ли они юнит или интеграционными, с моками или без — какая разница? Этому вопросу помоему уделяется неоправдано много внимания.
G>Можно долго рассказывать о том как не написать плохой код, но следование всем этим правилам не гарантирует что код получится хорошим. G>С тестами аналогично. Можно исключить все антипаттерны в своих тестах, но не факт что тесты получатся хорошие.
G>Я уже писал что самый лучший способ изучать TDD — смотреть видеозаписи о том как люди пишут код по TDD.
А нужно ли вообще изучать TDD? Это пока вопрос открытый
Здравствуйте, Константин Б., Вы писали:
КБ>Тесты надо писать так: КБ>1. Чтобы они запускались автоматически КБ>2. Чтобы тестировали то что нужно.
Этого мало. Для того, чтобы тестами пользовались, они не должны сильно "напрягать" разаботчика.
Для этого нужно чтобы они были быстрыми (тогда их будут часто запускать) и простыми (тогда их легко писать).
Интеграционные тесты обоим этим критериям не удовлетворяют: они медленнее (т.к. в тесте задействовано сразу несколько модулей) и их сложнее писать (если модуль A использует модуль B и в модуле B нужно протестировать какой-нить хитрый случай, нужно будет сильно подумать какие данные подать на вход в A, чтобы в B пришли нужные данные).
КБ>А будут ли они юнит или интеграционными, с моками или без — какая разница? Этому вопросу помоему уделяется неоправдано много внимания.
Тогда странно, что ты так рьяно защищаешь интеграционные тесты.
Здравствуйте, Константин Б., Вы писали:
КБ>Здравствуйте, gandjustas, Вы писали:
G>>>>В таком контексте "один тест — один класс" — абсурд. G>>>>Надо понимать что когда написано "один тест — один класс", то дадеко не каждый класс имеется ввиду.
КБ>>>Ну вообще-то неплохо бы об этом сказать, прежде чем ожидать понимания. G>>Это сложно. Я, например, сходу не могу сказать чем отличается класс вообще, от того класса который имеется ввиду в этой фразе. КБ>Ну и ладно. Можно же просто рассказать о моках, о их пользе. А само применение моков оставить на усмотрение разработчика.
Но это все же презентация, в ней надо побольше громких, желательно безапелляционных, заявлений делать.
Ведь если честно все рассказать в презентации или в книге, то большинство скажет что это и так известно (что на самом деле является очень хорошей характеристикой). Хотя потом еще лет 10 цитировать будут.
КБ>>>Может тогда ну их нафиг эти правила, а? G>>Нет, нафиг такой подход, когда читаешь кучу таких "правил", а потом слемо им следуешь. G>>Это называется культ карго КБ>А нафига правила если им нельзя следовать?
Можно. Почитай по ссылке.
G>>На практике человек не может обычно написать тесты для всех сценариев A и B, может получиться так что A использует B таким образом, что B в таком сценарии не тестировался. КБ>Ага. Поэтому интеграционные тесты — рулят
Совсем не рулят. Потому что если не человек не смог для изолированных компонент написать достаточно полный test-suite, то в случае тестирования группы компонент он вряд ли покроет тестами даже 10% сценариев.
Вообще интеграционные тесты дают рост экспоненциальный количества тестов при увеличении связности и количества компонент. Тогда как количество unit-тестов растет линейно. Это уже не говоря о том что unit-тесты гораздо проще в написании, чем интеграционные.
КБ>>>Ага. Но вместо того чтобы это объяснить, придумываются глупые правила. G>>Сложно объяснять как правильно писать тесты, это также сложно как правильно писать код.
КБ>Тесты надо писать так: КБ>1. Чтобы они запускались автоматически КБ>2. Чтобы тестировали то что нужно.
Всего-то
А как определить что нужно тестировать?
А как писать тесты так, чтобы они не стали обузой?
А когда вообще писать тесты?
...
продолжать можно долго.
Для полноценной методаки тестирования нужно гораздо больше формализма и при этом должно быть понимание зачем это все делается.
КБ>А будут ли они юнит или интеграционными, с моками или без — какая разница? Этому вопросу помоему уделяется неоправдано много внимания.
Я думаю что этому вопросу уделяется слишком мало внимания, так как ответы на такие вопросы делают тестирование эффективным.
G>>Я уже писал что самый лучший способ изучать TDD — смотреть видеозаписи о том как люди пишут код по TDD. КБ>А нужно ли вообще изучать TDD? Это пока вопрос открытый
Изучать по-любоу нужно
Здравствуйте, Константин Б., Вы писали:
КБ>Для меня фраза "интерфейс определяется тестами" — бессмыслица. Если функциональные тесты еще хоть как-то можно вывести из функциональных требований, то юнит-тесты проектируются "из головы", а то и подгоняются под уже придуманный интерфейс.
Вот именно так и получается: тесты выдумываются "из головы" — и в это время в голову приходит понимание того, каким должен быть интерфейс. Здесь мы, разумеется, говорим об интерфейсе как наборе торчащих из модуля данных и методов, а не о т.н. "интерфейсе пользователя" — всяких разных кнопочках-менюшечках . Просто тест — это уже в каком-то смысле использование модуля, а практика показывает, что как бы хорошо модуль не был спроектирован и написан — с момента начала его эксплуатации о нем неминуемо узнаешь много нового и рука сама тянется к кнопке "переделать нафиг". Тесты позволяют нажать на эту кнопку чуть раньше — только и всего...
КБ>Нет. Но презентация запрещает писать один тест на несколько классов.
Презентацию не смотрел ввиду угребищности ее формата, поэтому на всякий случай уточню: прям вот так вот и запрещает? Или просто говорит о том, что это неудобно? Просто на самом деле в большинстве случаев оно именно так и есть — проще написать два похожих теста для двух разных сущностей, чем потом пялиться на красную полоску и гадать — "а из-за кого она на этот раз?" Есть, конечно, и исключения (скажем тестить внутренние классы независимо от класса-хозяина смысла, наверное, нет), но они, как обычно, лишь подтверждают правило. Ты можешь с ходу придумать случай, при котором два независимых класса потребовалось бы тестировать одни юнит- (не интеграционным, не функциональным, а именно модульным) тестом?
КБ>Вот на слайдах 180-186 там и говорится, что каждый тест должен тестировать один метод и один класс. КБ>Как еще такой подход назвать как не параноей?
180-186????
Будь у меня ФФ, хрен бы я до 180 страницы доклацался, вне зависимости от содержания. Юзабилити презентации, по ходу, в глубочайшей жопе(мало того, что требует ФФ, так еще и требует дикого количества кликов).
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, gandjustas, Вы писали:
HL>>>>Согласен. Есть куча приложений, в которых предметная область очень сложна и нетривиальна, конечно, реализовать их просто ну никак не получится. AVK>>>Да нет, дело не только в этом. Простота не должна быть в ущерб понятности. К примеру, linq запрос сложнее рукопашных циклов, но, обычно, значительно понятнее.
HL>>Эх, Linq, linq... как посмотришь на те запросы, которые он генерит (linq2sql), становится грустно. Да и подкрутить мало что можно — т.е. имеем очередной показательный пример Leaky Abstraction. G>А работают они очень даже прилично. G>Кроме этого ты бы руками в жизни не написал sql, который генерит Linq2sql из более-менее сложного linq запроса.
Нуда, нуда... сложные запросы.... Сложные запросы — не те, которые вытаскиывают кучу привязанных сущностей, а которые делают что-то нетривиальное. Вот с этим у linq2sql большие проблемы.
Здравствуйте, denisio_mcp, Вы писали:
_>1) таймаут при блокировке этой записи и истечении времени ожидания снятия блокировки _>2) deadlock _>3) отсутствие прав _>4) каскадное обновление каких-либо других объектов _>5) соответствие переданных данных constraintам БД _>6) отсутствие/наличие исключений при работе триггеров _>7) скорость поиска и изменения в VLDB-среде и опять же таймаут. _>8) соответствие типов переданных данных типам полей в БД.
_>Это если не особо думать, можно еще нарисовать столько же нюансов.
Чувак, прикинь, если для проверки GetCustomerByID нужно написать хренову тучу совершенно нетривиальных тестов, сколько же времени придётся убить, чтобы написать что-то более-сложное, чем Hello, World? Так можно и простейших сайтик с тремя таблицами превратить в многомиллионный проект с гигантской командой разработки (и тестирования).
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, gandjustas, Вы писали:
HL>>>>>Согласен. Есть куча приложений, в которых предметная область очень сложна и нетривиальна, конечно, реализовать их просто ну никак не получится. AVK>>>>Да нет, дело не только в этом. Простота не должна быть в ущерб понятности. К примеру, linq запрос сложнее рукопашных циклов, но, обычно, значительно понятнее.
HL>>>Эх, Linq, linq... как посмотришь на те запросы, которые он генерит (linq2sql), становится грустно. Да и подкрутить мало что можно — т.е. имеем очередной показательный пример Leaky Abstraction. G>>А работают они очень даже прилично. G>>Кроме этого ты бы руками в жизни не написал sql, который генерит Linq2sql из более-менее сложного linq запроса.
HL>Нуда, нуда... сложные запросы.... Сложные запросы — не те, которые вытаскиывают кучу привязанных сущностей, а которые делают что-то нетривиальное. Вот с этим у linq2sql большие проблемы.
Какие проблемы? Еще раз: с помощью linq ты сможешь написать такой запрос, который руками не напишешь в жизни. И работать он будет гораздо быстрее, ибо индексы и кеширование в БД.
Здравствуйте, iHateLogins, Вы писали:
HL>Чувак, прикинь, если для проверки GetCustomerByID нужно написать хренову тучу совершенно нетривиальных тестов, сколько же времени придётся убить, чтобы написать что-то более-сложное, чем Hello, World?
А кто тебе сказал, что разработка программ — это легко?
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, denisio_mcp, Вы писали:
_>>1) таймаут при блокировке этой записи и истечении времени ожидания снятия блокировки _>>2) deadlock _>>3) отсутствие прав _>>4) каскадное обновление каких-либо других объектов _>>5) соответствие переданных данных constraintам БД _>>6) отсутствие/наличие исключений при работе триггеров _>>7) скорость поиска и изменения в VLDB-среде и опять же таймаут. _>>8) соответствие типов переданных данных типам полей в БД.
_>>Это если не особо думать, можно еще нарисовать столько же нюансов.
HL>Чувак, прикинь, если для проверки GetCustomerByID нужно написать хренову тучу совершенно нетривиальных тестов, сколько же времени придётся убить, чтобы написать что-то более-сложное, чем Hello, World?
На самом деле только GetCustomerByID в стотыщ раз сложнее, чем hello world.
HL>Так можно и простейших сайтик с тремя таблицами превратить в многомиллионный проект с гигантской командой разработки (и тестирования).
С подходом в котором много методов типа GetCustomerByID это действительно так.
Для сайтиков с тремя таблицами нужны другие средства.
Здравствуйте, Eugeny__, Вы писали:
E__>Будь у меня ФФ, хрен бы я до 180 страницы доклацался, вне зависимости от содержания. Юзабилити презентации, по ходу, в глубочайшей жопе(мало того, что требует ФФ, так еще и требует дикого количества кликов).
А что ты еще хотел от любителя тестов? Он, небось, и программирует так — сотни классов с 1-2 строчками кода для решения простой задачи.
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, denisio_mcp, Вы писали:
_>>1) таймаут при блокировке этой записи и истечении времени ожидания снятия блокировки _>>2) deadlock _>>3) отсутствие прав _>>4) каскадное обновление каких-либо других объектов _>>5) соответствие переданных данных constraintам БД _>>6) отсутствие/наличие исключений при работе триггеров _>>7) скорость поиска и изменения в VLDB-среде и опять же таймаут. _>>8) соответствие типов переданных данных типам полей в БД.
HL>Чувак, прикинь, если для проверки GetCustomerByID нужно написать хренову тучу совершенно нетривиальных тестов, сколько же времени придётся убить,
Если на рабочей системе косяк вылезет где-то в выделенном, времени на поиск бага уйдет на пару порядков больше. В лучшем случае. И стоимость такого ремонта может очень сильно зашкалить.
А насчет нетривиальности тестов — так за то программисту и платят, чтобы нетривиальные вещи делать тривиальными.
Здравствуйте, gandjustas, Вы писали:
HL>>Нуда, нуда... сложные запросы.... Сложные запросы — не те, которые вытаскиывают кучу привязанных сущностей, а которые делают что-то нетривиальное. Вот с этим у linq2sql большие проблемы.
G>Какие проблемы? Еще раз: с помощью linq ты сможешь написать такой запрос, который руками не напишешь в жизни. И работать он будет гораздо быстрее, ибо индексы и кеширование в БД.
Ибо индексы Ибо кеширование
Ну, Петросян, уморил
Ты думаешь база данных каким-то волшебным способом сделает из говно-запросов, генеренных l2s, конфетку Индексы сама создаст, закэширует что нужно, а что не нужно — не закэширует
Здравствуйте, Пацак, Вы писали:
HL>>Чувак, прикинь, если для проверки GetCustomerByID нужно написать хренову тучу совершенно нетривиальных тестов, сколько же времени придётся убить, чтобы написать что-то более-сложное, чем Hello, World?
П>А кто тебе сказал, что разработка программ — это легко?
Дом без гвоздей уже собрал? Лес ножовкой попилил? На дачу пешком ходищь?
Инструменты на то и нужны, чтобы делать жизнь проще. Если вы сначала стреляете себе в ногу (юнит-тесты), ползёте с черепашьей скоростью, утверждая, что зато "так надёжнее" — то это ваши проблемы и проблемы ваших заказчиков. Рано или поздно они не оценят такой, хм, производительности, и выберут того, кто делает свою работу быстрее. Пусть код не будет покрыт юнит-тестами и API зацементирован этими самыми тестами, зато он будет живой, развивающийся и легкомодифицируемый.
КБ>Ваше? А презентацию то читали? КБ>Вот на слайдах 180-186 там и говорится, что каждый тест должен тестировать один метод и один класс. Если не дай бог у нас задействовано два класса — то это уже никакой не юнит-тест, а интегрейшн-тест. Поэтому надо второй класс обязательно заменить моком. А то ведь из-за бага в классе А могут заподозрить невинновный класс B.
Это гайдлайн. Очень разумная, но все же рекомендация. Разумная потому, что если тестировать методы отдельно, то изолировать тесты друг от друга очень просто. Если, например, нужда в каком-то методе отпала, то достаточно будет выкинуть лишь один тест и не перелопачивать колбасу теста, который проверяет все методы класса друг за другом.
Например, я стараюсь делать так
для сколько-нибудь сложной логики. (предвидя вопросы — написание этих у меня тестов занимает минут пять от силы)
Рекомендация же потому, что программист сам решает, как именно писать тесты. Например, я пишу вышеперечисленное только в случаях, когда это стоит того. Я пишу код и я знаю, какие тут могут быть косяки. Поэтому я и стараюсь проверить код в различных условиях. Это и дает возможность спать спокойно.
Далее — совет заменять класс А моком очень правильный. Нет, ничего страшного в использовании конкретных классах в тестах нет, более того, подобные тесты добавляют уверенности в том, что класс А отлично интегрируется с классом Б. Я и сам так постоянно делаю. Но там правильно отмечено — если придеживаться подхода "один тест — один класс и один метод", то это приносит свои бенефиты. Например, в условиях командной разработки, когда класс А пишет Вася, а класс Б пишет Петя, и Петя может, во-первых, протестировать свой код в изоляции от кода Васи, как раз для того, чтобы не получить ложное срабатывание из-за Васиного косяка. Ну и, кроме того, от класса А может банально существовать только лишь интерфейс к тому времени, когда Петя уже написал свой класс Б.
Здравствуйте, gandjustas, Вы писали:
_>>>Это если не особо думать, можно еще нарисовать столько же нюансов.
HL>>Чувак, прикинь, если для проверки GetCustomerByID нужно написать хренову тучу совершенно нетривиальных тестов, сколько же времени придётся убить, чтобы написать что-то более-сложное, чем Hello, World? G>На самом деле только GetCustomerByID в стотыщ раз сложнее, чем hello world.
Если у вас GetCustomerByID — это циклопический нетривиальный проект, в 100 000 раз сложнее Hello World, то сайтик с тремя таблицами превратится просто в "Манхэттэнский проект"
Здравствуйте, Константин Б., Вы писали:
G>>Далеко не все знают как надо. КБ>Ага. Но вместо того чтобы это объяснить, придумываются глупые правила.
Объяснить невозможно. Тот самый синдром землекопа "некогда нам тут фигней заниматься".
Можно лишь показать на примере.
Здравствуйте, gandjustas, Вы писали:
G>Я уже писал что самый лучший способ изучать TDD — смотреть видеозаписи о том как люди пишут код по TDD.
Гораздо лучше заполучить test infected разработчика на проект.
S>Тесты — дело хорошее, но. Сроки и бюджеты для нехайтек проектов порой берутся с потолка. Поэтому работают все в спешке. Получается дилема: (система с тестами, но недоделанная ИЛИ система без тестов, но имеющая всю функциональность, кое как протестированную). Очевидно, всегда годится второй вариант. Если это состояние достигнуто, можно систему впарить и исправить баги уже за доп. деньги.
Мой опыт показывает, что с тестами скорость разработки увеличивается раза в два.
1. Если конструктор Customer() кинет исключение, тест не пройдет.
2. Если Create() кинет исключение, тест не пройдет
3. Если GetCustomerById() вернет что-то отличное от ожидаемого, тест провалится.
4. Если впоследствии кто-то умный решит играться регистром имен в конструкторах, сеттерах или еще где, тест свалится
Здравствуйте, iHateLogins, Вы писали:
HL>Инструменты на то и нужны, чтобы делать жизнь проще. Если вы сначала стреляете себе в ногу (юнит-тесты), ползёте с черепашьей скоростью, утверждая, что зато "так надёжнее" — то это ваши проблемы и проблемы ваших заказчиков. Рано или поздно они не оценят такой, хм, производительности, и выберут того, кто делает свою работу быстрее. Пусть код не будет покрыт юнит-тестами и API зацементирован этими самыми тестами, зато он будет живой, развивающийся и легкомодифицируемый.
Круто, где ж ты раньше-то был?!! Значит, говоришь, отказ от юнит-тестов делает код живым, развивающимся и легкомодифицируемым? Вот где она, серебрянная пуля-то зарыта. А то впаривают, понимаешь, про архитектуру, алгоритмы, улучшение навыков через изучение языков разных парадигм и т.п., а тут раз — и живой, развивающийся и легкомодифицируемы код!
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Luck in life always exists in the form of an abstract class that cannot be instantiated directly and needs to be inherited by hard work and dedication.
Здравствуйте, gandjustas, Вы писали:
G>Какие проблемы? Еще раз: с помощью linq ты сможешь написать такой запрос, который руками не напишешь в жизни. И работать он будет гораздо быстрее, ибо индексы и кеширование в БД.
Э нет. Руками я такие запросы напишу, которые linq-ом не напишешь в жизни.
Ах да, а причем здесь индексы и кэширование БД? По твоему они работают только для linq-запросов, а то что я руками написал — СУБД мне говорит человеческим голосом: "А хрен тебе кеширование и индексы — твой запрос написан руками"
Здравствуйте, iHateLogins, Вы писали:
HL>Для танкистов: в самих юнит-тестах проблем нет, проблема в том, что ими неумело пользуются, цементируя код и лишая себя возможности что-либо переделать (т.к. дорого, заказчик не одобрит)
Юнит-тесты никогда, ни при каких условиях не способны "зацементировать" код. Критерий тестируемости кода — минимально возможное количество зависимостей. Когда это достигается, замена кода одного юнита другим (рефакторинг) происходит настолько безболезненно, что остальные модули этого просто не замечают.
У Вас лично юнит-тесты когда-либо приводили к, как Вы это называете, зацементированному коду?
HL>Ну так все копают-то, нетленку вояют единицы... В ERP и сайтостроении работает подавляющее большинство разработчиков, мало кто пишет математические алгоритмы или архиваторы (где, юнит-тесты просто АРХИ-НУЖНЫ!).
Юнит-тесты нужны везде. Period.
Здравствуйте, yuriylsh, Вы писали:
HL>>Инструменты на то и нужны, чтобы делать жизнь проще. Если вы сначала стреляете себе в ногу (юнит-тесты), ползёте с черепашьей скоростью, утверждая, что зато "так надёжнее" — то это ваши проблемы и проблемы ваших заказчиков. Рано или поздно они не оценят такой, хм, производительности, и выберут того, кто делает свою работу быстрее. Пусть код не будет покрыт юнит-тестами и API зацементирован этими самыми тестами, зато он будет живой, развивающийся и легкомодифицируемый.
Y>Круто, где ж ты раньше-то был?!! Значит, говоришь, отказ от юнит-тестов делает код живым, развивающимся и легкомодифицируемым? Вот где она, серебрянная пуля-то зарыта. А то впаривают, понимаешь, про архитектуру, алгоритмы, улучшение навыков через изучение языков разных парадигм и т.п., а тут раз — и живой, развивающийся и легкомодифицируемы код!
Здравствуйте, iHateLogins, Вы писали:
HL>Тебе впаривают?
Это ты к чему спросил?
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Luck in life always exists in the form of an abstract class that cannot be instantiated directly and needs to be inherited by hard work and dedication.
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, gandjustas, Вы писали:
HL>>>Нуда, нуда... сложные запросы.... Сложные запросы — не те, которые вытаскиывают кучу привязанных сущностей, а которые делают что-то нетривиальное. Вот с этим у linq2sql большие проблемы.
G>>Какие проблемы? Еще раз: с помощью linq ты сможешь написать такой запрос, который руками не напишешь в жизни. И работать он будет гораздо быстрее, ибо индексы и кеширование в БД.
HL> Ибо индексы Ибо кеширование
HL>Ну, Петросян, уморил
Бросай колеса принимать.
HL>Ты думаешь база данных каким-то волшебным способом сделает из говно-запросов, генеренных l2s, конфетку
Совсем не волшебным. Оптимизатор есть. HL>Индексы сама создаст, закэширует что нужно, а что не нужно — не закэширует
Индексы ты создашь.
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, gandjustas, Вы писали:
_>>>>Это если не особо думать, можно еще нарисовать столько же нюансов.
HL>>>Чувак, прикинь, если для проверки GetCustomerByID нужно написать хренову тучу совершенно нетривиальных тестов, сколько же времени придётся убить, чтобы написать что-то более-сложное, чем Hello, World? G>>На самом деле только GetCustomerByID в стотыщ раз сложнее, чем hello world.
HL>Если у вас GetCustomerByID — это циклопический нетривиальный проект, в 100 000 раз сложнее Hello World, то сайтик с тремя таблицами превратится просто в "Манхэттэнский проект"
Ты читать умеешь?
Для сайтиков с тремя таблицами нужны другие средства.
Здравствуйте, landerhigh, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
G>>Я уже писал что самый лучший способ изучать TDD — смотреть видеозаписи о том как люди пишут код по TDD. L>Гораздо лучше заполучить test infected разработчика на проект.
Тоже вариент, только такие разработчики не ищут толпами работу.
L>1. Если конструктор Customer() кинет исключение, тест не пройдет. L>2. Если Create() кинет исключение, тест не пройдет L>3. Если GetCustomerById() вернет что-то отличное от ожидаемого, тест провалится. L>4. Если впоследствии кто-то умный решит играться регистром имен в конструкторах, сеттерах или еще где, тест свалится
L>Нормальный тест.
При этом то, что он тестирует — тривиально. А вот если допустим Федя дропнет индекс по ID или
сделает его неуникальным — то этот тест будет продолжать работать, особенно учитывая что вместо базы
подсовывают или мок или пустую базу. А ведь подобного рода ошибка — это блокер. И юнит тест его не
ловит в данном случае.
Заметим также, что все говорят что "другие тесты тоже надо делать", но никто ни слова не говорит что
это за тесты, как их надо делать и т.п. Все увлеченно как бы это сказать... фапают на юнит тесты.
А панацейка-то так себе, создает проблем не меньше, чем решает.
А ведь эти "более другие тесты" тоже в состоянии обнаружить поломку API в данном методе. Стоит ли
дублировать?
Здравствуйте, _d_m_, Вы писали:
___>Здравствуйте, gandjustas, Вы писали:
G>>Какие проблемы? Еще раз: с помощью linq ты сможешь написать такой запрос, который руками не напишешь в жизни. И работать он будет гораздо быстрее, ибо индексы и кеширование в БД.
___>Э нет. Руками я такие запросы напишу, которые linq-ом не напишешь в жизни.
Ну да, CTE на linq не напишешь, но я не об этом.
Возьми сложный запрос из своей программы (c let, аггрегацией, нетривиальной проекцией) и не заглядывая какой sql он генерит напиши свой вариант sql кода.
___>Ах да, а причем здесь индексы и кэширование БД? По твоему они работают только для linq-запросов, а то что я руками написал — СУБД мне говорит человеческим голосом: "А хрен тебе кеширование и индексы — твой запрос написан руками"
Притом что львиная доля производительности запросов вытягивается индексами. Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
Здравствуйте, dmz, Вы писали:
L>>Нормальный тест. dmz>При этом то, что он тестирует — тривиально. А вот если допустим Федя дропнет индекс по ID или
Опыт показывает, что стоит не протестировать что-то тривиальное, как из этого "тривиального" отрастают неуловимые баги. dmz>сделает его неуникальным — то этот тест будет продолжать работать, особенно учитывая что вместо базы dmz>подсовывают или мок или пустую базу. А ведь подобного рода ошибка — это блокер. И юнит тест его не dmz>ловит в данном случае.
Юнит тесты в общем случае не тестируют производительность. dmz>А ведь эти "более другие тесты" тоже в состоянии обнаружить поломку API в данном методе. Стоит ли dmz>дублировать?
Лучше перебдеть. От двух строчек с ассертами среднестатистический программер не переломится.
L>>>Нормальный тест. dmz>>При этом то, что он тестирует — тривиально. А вот если допустим Федя дропнет индекс по ID или L>Опыт показывает, что стоит не протестировать что-то тривиальное, как из этого "тривиального" отрастают неуловимые баги.
Опыт у всех разный.
dmz>>сделает его неуникальным — то этот тест будет продолжать работать, особенно учитывая что вместо базы dmz>>подсовывают или мок или пустую базу. А ведь подобного рода ошибка — это блокер. И юнит тест его не
dmz>>ловит в данном случае. L>Юнит тесты в общем случае не тестируют производительность.
Это критическией дефект, приводящий к неработоспособности системы вообще. Если напрячься, можно придумать еще дефектов,
которые данный тест не поймает никогда, в силу подхода.
L>Лучше перебдеть. От двух строчек с ассертами среднестатистический программер не переломится.
Количество и объем юнит-тестов растут комбинаторно. Плюс затраты на их рефакторинг при различных
изменениях.
Оно конечно понятно, откуда берется такая приверженность к ним — концепция юнит тестов проста, понятна, не требует
особых дополнительных знаний и больших затрат на организацию инфраструктуры, в отличие от прочих тестов.
К тому же, настойчиво продвигается продавцами змеиного масла. Но вот большой разницы в качестве проектов, которые этими тестами
переполнены, с проектами где их вообще нет — как-то не наблюдается. Если только колебания в ту и в другую сторону.
Заметим, что отсутствие юнит-тестов — не равно отсутствию автоматических тестов.
Здравствуйте, dmz, Вы писали:
L>>1. Если конструктор Customer() кинет исключение, тест не пройдет. L>>2. Если Create() кинет исключение, тест не пройдет L>>3. Если GetCustomerById() вернет что-то отличное от ожидаемого, тест провалится. L>>4. Если впоследствии кто-то умный решит играться регистром имен в конструкторах, сеттерах или еще где, тест свалится
L>>Нормальный тест.
dmz>При этом то, что он тестирует — тривиально.
В тривиальном коде при тривиальных его модификациях появляются совсем нетривиальные баги.
dmz>А вот если допустим Федя дропнет индекс по ID или dmz>сделает его неуникальным — то этот тест будет продолжать работать, особенно учитывая что вместо базы dmz>подсовывают или мок или пустую базу. А ведь подобного рода ошибка — это блокер. И юнит тест его не dmz>ловит в данном случае.
Тоже самое может произойти и в продакшене, тесты вам не помогут.
dmz>Заметим также, что все говорят что "другие тесты тоже надо делать", но никто ни слова не говорит что dmz>это за тесты, как их надо делать и т.п. Все увлеченно как бы это сказать... фапают на юнит тесты. dmz>А панацейка-то так себе, создает проблем не меньше, чем решает.
Никаких проблем не создаются.
L>>>>Нормальный тест. dmz>>>При этом то, что он тестирует — тривиально. А вот если допустим Федя дропнет индекс по ID или L>>Опыт показывает, что стоит не протестировать что-то тривиальное, как из этого "тривиального" отрастают неуловимые баги. dmz>Опыт у всех разный.
Тогда нужно говорить о вкусе устриц с теми, кто их ел. L>>Юнит тесты в общем случае не тестируют производительность. dmz>Это критическией дефект, приводящий к неработоспособности системы вообще. Если напрячься, можно придумать еще дефектов, dmz>которые данный тест не поймает никогда, в силу подхода.
Я не понял, кто-то говорит, что одних юнит-тестов достаточно? Кто Вам мешает, делайте функциональные и нагрузочные тесты, пользователи только спасибо скажут. Только вот рановато тестировать производительность, если GetCustomerById() "иногда" падает. L>>Лучше перебдеть. От двух строчек с ассертами среднестатистический программер не переломится. dmz>Количество и объем юнит-тестов растут комбинаторно. Плюс затраты на их рефакторинг при различных dmz>изменениях.
Нет никаких затрат на рефакторинг тестов. По крайней мере затраты на поддержание тестов в актуальном состоянии на порядок меньше затрат на рефакторинг основного кода и на три-четыре порядка меньше затрат на поиск бага в рабочей системе. Если у Вас тесты такие, что их поддерживать сложно, мне страшно даже предположить, что там в основном коде творится. dmz>К тому же, настойчиво продвигается продавцами змеиного масла. Но вот большой разницы в качестве проектов, которые этими тестами dmz>переполнены, с проектами где их вообще нет — как-то не наблюдается. Если только колебания в ту и в другую сторону.
Наблюдается. Очень сильная разница. Не в пользу землекопного кода, конечно. dmz>Заметим, что отсутствие юнит-тестов — не равно отсутствию автоматических тестов.
Здравствуйте, dmz, Вы писали:
dmz>Это критическией дефект, приводящий к неработоспособности системы вообще. Если напрячься, можно придумать еще дефектов, dmz>которые данный тест не поймает никогда, в силу подхода.
Это дефект равертывания, а не разрабтки. Тестами он не ловится в принципе.
Если же такой дефект допущен при разработке, то он сразу же отловится приемочными тестами (ручными или еще какими).
dmz>Количество и объем юнит-тестов растут комбинаторно.
Неверно. Количество unit-тестов растет линейно, а объем практически не растет.
твое утверждение верно для "других тестов".
dmz>Плюс затраты на их рефакторинг при различных изменениях.
Мало отличаются от 0.
dmz>Оно конечно понятно, откуда берется такая приверженность к ним — концепция юнит тестов проста, понятна, не требует dmz>особых дополнительных знаний и больших затрат на организацию инфраструктуры, в отличие от прочих тестов.
Всего-то, также позволяет покрыть тестами гораздо больше сценариев при тех де усислиях
dmz>К тому же, настойчиво продвигается продавцами змеиного масла. Но вот большой разницы в качестве проектов, которые этими тестами dmz>переполнены, с проектами где их вообще нет — как-то не наблюдается. Если только колебания в ту и в другую сторону.
Действительно не наблюдается, если система переполнена тестами, то затраты идут на поддержку тестов, если нету тестов, то затраты идут на исправление багов.
А вот если тестов столько сколько нужно, то получается и качество высокое и время разработки низкое.
dmz>Заметим, что отсутствие юнит-тестов — не равно отсутствию автоматических тестов.
но практически всегда отсуствие unit-тестов приводит к тому что покрытие сценариев оказывается в разы меньше
Здравствуйте, gandjustas, Вы писали:
___>>Ах да, а причем здесь индексы и кэширование БД? По твоему они работают только для linq-запросов, а то что я руками написал — СУБД мне говорит человеческим голосом: "А хрен тебе кеширование и индексы — твой запрос написан руками" G>Притом что львиная доля производительности запросов вытягивается индексами. Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
Это только плюс оптимизатору. Но он таким же образом поступает с любым другим запросом в том числе ручным.
Здравствуйте, _d_m_, Вы писали:
___>Здравствуйте, gandjustas, Вы писали:
___>>>Ах да, а причем здесь индексы и кэширование БД? По твоему они работают только для linq-запросов, а то что я руками написал — СУБД мне говорит человеческим голосом: "А хрен тебе кеширование и индексы — твой запрос написан руками" G>>Притом что львиная доля производительности запросов вытягивается индексами. Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
___>Это только плюс оптимизатору. Но он таким же образом поступает с любым другим запросом в том числе ручным.
Таким образом linq запросы делают sql не намного хуже, чем вручную.
А широкие возможности динамического составления запросов в linq позволяют с помощью него использовать базу гораздо эффективнее.
Так что наезды на linq совершенно безосоновательны.
Здравствуйте, gandjustas, Вы писали:
___>>>>Ах да, а причем здесь индексы и кэширование БД? По твоему они работают только для linq-запросов, а то что я руками написал — СУБД мне говорит человеческим голосом: "А хрен тебе кеширование и индексы — твой запрос написан руками" G>>>Притом что львиная доля производительности запросов вытягивается индексами. Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
___>>Это только плюс оптимизатору. Но он таким же образом поступает с любым другим запросом в том числе ручным. G>Таким образом linq запросы делают sql не намного хуже, чем вручную. G>А широкие возможности динамического составления запросов в linq позволяют с помощью него использовать базу гораздо эффективнее.
G>Так что наезды на linq совершенно безосоновательны.
Какие еще наезды на линк?
Еще раз, для тех кто в танке:
HL>Нуда, нуда... сложные запросы.... Сложные запросы — не те, которые вытаскиывают кучу привязанных сущностей, а которые делают что-то нетривиальное. Вот с этим у linq2sql большие проблемы.
Какие проблемы? Еще раз: с помощью linq ты сможешь написать такой запрос, который руками не напишешь в жизни. И работать он будет гораздо быстрее, ибо индексы и кеширование в БД.
1. Утверждение, что линк генерит суперволшебные запросы, которые я не напишу в жизни — неверно. Руками можно написать действительно нетривиальные запросы. Которые на линке ну никак нельзя сделать.
2. Утверждение, что суперволшебные запросы линка работают гораздо быстрее, чем ручные запросы абсолютная ересь. Особенно в купе с аргументами про индексы и кэширование.
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
G>>Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
L>И каким же образом он узнает, что запрос сгенерирован LINQ-ом, а не руками?
Здравствуйте, Lloyd, Вы писали:
L>Здравствуйте, gandjustas, Вы писали:
G>>Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
L>И каким же образом он узнает, что запрос сгенерирован LINQ-ом, а не руками?
Ну дак я ему уже так толсто намекал. Хотелось бы узнать природу этого чуда.
Здравствуйте, gandjustas, Вы писали:
G>>>Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
L>>И каким же образом он узнает, что запрос сгенерирован LINQ-ом, а не руками?
G>Никак, а оно ему надо?
К чему тогда добавка "по запросу сгенерированному с помощью Linq"?
Это относится к любому запросу, а не только LINQ-овскому. Заслуги LINQ-а тут нет никакой.
Здравствуйте, _d_m_, Вы писали:
___>Здравствуйте, gandjustas, Вы писали:
___>>>>>Ах да, а причем здесь индексы и кэширование БД? По твоему они работают только для linq-запросов, а то что я руками написал — СУБД мне говорит человеческим голосом: "А хрен тебе кеширование и индексы — твой запрос написан руками" G>>>>Притом что львиная доля производительности запросов вытягивается индексами. Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
___>>>Это только плюс оптимизатору. Но он таким же образом поступает с любым другим запросом в том числе ручным. G>>Таким образом linq запросы делают sql не намного хуже, чем вручную. G>>А широкие возможности динамического составления запросов в linq позволяют с помощью него использовать базу гораздо эффективнее.
G>>Так что наезды на linq совершенно безосоновательны.
___>Какие еще наезды на линк? ___>Еще раз, для тех кто в танке: ___>
HL>>Нуда, нуда... сложные запросы.... Сложные запросы — не те, которые вытаскиывают кучу привязанных сущностей, а которые делают что-то нетривиальное. Вот с этим у linq2sql большие проблемы.
___>Какие проблемы? Еще раз: с помощью linq ты сможешь написать такой запрос, который руками не напишешь в жизни. И работать он будет гораздо быстрее, ибо индексы и кеширование в БД.
А ты пост этого оратора перед процитированным почитай.
___>1. Утверждение, что линк генерит суперволшебные запросы, которые я не напишу в жизни — неверно.
Да я уже привел сценарий как проверить крутость линка. Попробуйте на досуге переписать сложный linq в sql, не заглядывая что там linq генерит.
___>Руками можно написать действительно нетривиальные запросы. Которые на линке ну никак нельзя сделать.
Это только потому что linq слабее sql как язык.
___>2. Утверждение, что суперволшебные запросы линка работают гораздо быстрее, чем ручные запросы абсолютная ересь. Особенно в купе с аргументами про индексы и кэширование.
ты не понял, linq позволяет генерить запросы так что они будут работать быстрее, чем если писать sql ручками, за счет того что у linq гораздо больше возможностей динамической генерации запросов.
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Lloyd, Вы писали:
L>>Здравствуйте, gandjustas, Вы писали:
G>>>Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
L>>И каким же образом он узнает, что запрос сгенерирован LINQ-ом, а не руками?
G>Никак, а оно ему надо?
Ну ты же сказал, что SQL запросы от линка гораздо быстрее: т.к. индексы, кэширование в БД, оптимизатор умный.
Я начинаю догадываться: SQL запросы которые ты написал руками тормозили безбожно
Здравствуйте, gandjustas, Вы писали:
___>>2. Утверждение, что суперволшебные запросы линка работают гораздо быстрее, чем ручные запросы абсолютная ересь. Особенно в купе с аргументами про индексы и кэширование. G>ты не понял, linq позволяет генерить запросы так что они будут работать быстрее, чем если писать sql ручками, за счет того что у linq гораздо больше возможностей динамической генерации запросов.
Это не только я не понял. Это ты написал так, что понять твой посыл можно было только так, как сделали это как минимум 3 человека на этом форуме.
Про динамическу генерацию, пжлста, на примерах, на пальцах. А то в теории косинус в военное время может дотигать 6. Ну так просим пример, когда есть у нас линк запрос — с одними значениями параметров — такой SQL, с другими — такой вот другой SQL.
Здравствуйте, gandjustas, Вы писали:
___>>2. Утверждение, что суперволшебные запросы линка работают гораздо быстрее, чем ручные запросы абсолютная ересь. Особенно в купе с аргументами про индексы и кэширование. G>ты не понял, linq позволяет генерить запросы так что они будут работать быстрее, чем если писать sql ручками, за счет того что у linq гораздо больше возможностей динамической генерации запросов.
Расскажешь, как на LINQ-е fulltext запрос написать? А то вот руками я могу, а вот на LINQ-е все как-то не выходит.
Здравствуйте, _d_m_, Вы писали:
___>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, Lloyd, Вы писали:
L>>>Здравствуйте, gandjustas, Вы писали:
G>>>>Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
L>>>И каким же образом он узнает, что запрос сгенерирован LINQ-ом, а не руками?
G>>Никак, а оно ему надо?
___>Ну ты же сказал, что SQL запросы от линка гораздо быстрее: т.к. индексы, кэширование в БД, оптимизатор умный.
Ссылку.
___>Я начинаю догадываться: SQL запросы которые ты написал руками тормозили безбожно
Не, я таких запросов, как с помощью Linq не писал никогда.
У меня был один запрос, который давал SQL примерно на два листа A4, при этом он работал достаточно быстро.
Такой запрос я бы просто физически не нарисовал руками, а если бы даже наприсовал, то замучался бы его поддерживать.
Здравствуйте, gandjustas, Вы писали:
HL>>Ты думаешь база данных каким-то волшебным способом сделает из говно-запросов, генеренных l2s, конфетку G>Совсем не волшебным. Оптимизатор есть.
Какой еще в l2s оптимизатор? Эта шняга тупо проецирует дерево на sql, вообще не догадывается о планах запросов.
HL>>Индексы сама создаст, закэширует что нужно, а что не нужно — не закэширует G>Индексы ты создашь.
Индексы я сам сделаю, план оптимизирую, хинты расставлю... на кой ляд этот l2s нужен-то?
Здравствуйте, gandjustas, Вы писали:
G>>>>>Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
L>>>>И каким же образом он узнает, что запрос сгенерирован LINQ-ом, а не руками?
G>>>Никак, а оно ему надо?
___>>Ну ты же сказал, что SQL запросы от линка гораздо быстрее: т.к. индексы, кэширование в БД, оптимизатор умный. G>Ссылку.
___>>Я начинаю догадываться: SQL запросы которые ты написал руками тормозили безбожно G>Не, я таких запросов, как с помощью Linq не писал никогда.
Вот где собака порылась.
G>У меня был один запрос, который давал SQL примерно на два листа A4, при этом он работал достаточно быстро. G>Такой запрос я бы просто физически не нарисовал руками, а если бы даже наприсовал, то замучался бы его поддерживать.
Здравствуйте, gandjustas, Вы писали:
G>Притом что львиная доля производительности запросов вытягивается индексами. Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
Неохота мне спорить с теми, кто так сильно плавает в теме.
Здравствуйте, gandjustas, Вы писали:
_>>>>>Это если не особо думать, можно еще нарисовать столько же нюансов.
HL>>>>Чувак, прикинь, если для проверки GetCustomerByID нужно написать хренову тучу совершенно нетривиальных тестов, сколько же времени придётся убить, чтобы написать что-то более-сложное, чем Hello, World? G>>>На самом деле только GetCustomerByID в стотыщ раз сложнее, чем hello world.
HL>>Если у вас GetCustomerByID — это циклопический нетривиальный проект, в 100 000 раз сложнее Hello World, то сайтик с тремя таблицами превратится просто в "Манхэттэнский проект" G>Ты читать умеешь?
G>
G>Для сайтиков с тремя таблицами нужны другие средства.
Ну так ты GetCustomerByID уже превратил в нетривиальный проект, я даже в страшном сне не представлю, во что превратиться проект с 1000 таблицами.
Здравствуйте, iHateLogins, Вы писали:
HL>Чувак, прикинь, если для проверки GetCustomerByID нужно написать хренову тучу совершенно нетривиальных тестов, сколько же времени придётся убить, чтобы написать что-то более-сложное, чем Hello, World? Так можно и простейших сайтик с тремя таблицами превратить в многомиллионный проект с гигантской командой разработки (и тестирования).
Здравствуйте, landerhigh, Вы писали:
HL>>Для танкистов: в самих юнит-тестах проблем нет, проблема в том, что ими неумело пользуются, цементируя код и лишая себя возможности что-либо переделать (т.к. дорого, заказчик не одобрит) L>Юнит-тесты никогда, ни при каких условиях не способны "зацементировать" код. Критерий тестируемости кода — минимально возможное количество зависимостей. Когда это достигается, замена кода одного юнита другим (рефакторинг) происходит настолько безболезненно, что остальные модули этого просто не замечают.
L>У Вас лично юнит-тесты когда-либо приводили к, как Вы это называете, зацементированному коду?
Да. Во многих проектах было решение сверху, или "так повелось". по разному. И везде при переработках люди открывали для себя (я поражаюсь!), что абстракция на уровне модулей описывает зависимости на момент написания модуля. В реальной жизни при доработках в системе редко приходится дорабатывать один модуль, часто появляются перекрёстные зависимости и пр. И вся аккуратная "архитектура" летит к чёрту. И юнит-тесты просто тихо-мирно "умирают": все понимают, что это неоправданно дорогое удовольствие.
Поэтому с годами понимаешь, что писать надо так, чтобы было проще дорабатывать. Просто тупо писать меньше кода, можно даже хардкодить какие-то краевые случаи, писать по возможности проще и понятнее. И не делать абстракций, в долговременном существовании которых не уверен.
Да, еще "еретиковая" (по-вашему мысль: код, написанный на структурном подходе (статические функции + структуры) живёт и дорабатывается как правило проще и дешевле, чем "правильный" ООП-код. Понятно, что в реальной жизни нет "чистого ООП" и "чистого структурного программирования", но тем не менее "статические функции + классы-структуры" развиваются проще.
HL>>Ну так все копают-то, нетленку вояют единицы... В ERP и сайтостроении работает подавляющее большинство разработчиков, мало кто пишет математические алгоритмы или архиваторы (где, юнит-тесты просто АРХИ-НУЖНЫ!). L>Юнит-тесты нужны везде. Period.
Делайте как хотите. Понимание применимости технологий к конкретным предметным областям и заказчикам приходит с годами.
Здравствуйте, _d_m_, Вы писали: ___>Это не только я не понял. Это ты написал так, что понять твой посыл можно было только так, как сделали это как минимум 3 человека на этом форуме. ___>Про динамическу генерацию, пжлста, на примерах, на пальцах. А то в теории косинус в военное время может дотигать 6. Ну так просим пример, когда есть у нас линк запрос — с одними значениями параметров — такой SQL, с другими — такой вот другой SQL.
Ты мне на слово поверишь, что запрос со .Skip(x) даст разный SQL для x = 0 и для x = 10?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, iHateLogins, Вы писали: HL>Какой еще в l2s оптимизатор? Эта шняга тупо проецирует дерево на sql, вообще не догадывается о планах запросов.
А в нём оптимизатор не шибко-то и нужен. Так, чтобы повыкидывать очевидные вещи (на которые у SQL оптимизатора уже времени нет). HL>Индексы я сам сделаю, план оптимизирую, хинты расставлю... на кой ляд этот l2s нужен-то?
Ну, например, чтобы избавить тебя от нудной отладки динамического SQL. Потому как статическим невозможно эффективно все сценарии обработать.
Тут где-то IT приводил пример того, как переписали на Linq один запросец для этого сайта. До Linq лучшие собаководы даже с поллитрой не рисковали динамически генерировать разные версии SQL для разных сценариев.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, landerhigh, Вы писали:
L>>>Поднимите руки те, кому не приходится отлаживать свой собственный код в отладчике. L>>Юнит-тестирование избавляет от отладчика? L>Практически полностью. L>>А в самих тестах ошибки исключены? Orly? L>Практичски полностью.
Ну вообще-то в тестах ошибки не реже, особенно в сложных:)) Но они другого плана, обычно ортогональны ошибкам в коде. И исключение ошибок с обеих сторон даёт в итоге достаточно устойчивый результат.
L>Я правильно понимаю, что все собравшиеся здесь профессионалы не видят ничего ненормального в том, что только что написанный код нужно ковырять отладчиком?
Когда был молодым и зеленым мне многие вещи казались очевидными. Например очевидным казалось что написанный код надо проверить на функциональность.
Со временем, поработав с большим к-вом програмистов, я понял что многие совсем не так относятся к коду. Для многих стирается грань между "написать код" и "написать работающий код".
Причина в непонимании или в непонимании ответственности? стоит разобраться.
Здравствуйте, iHateLogins, Вы писали:
HL>Юнит-тесты уже становятся параноей, в 99% они превращаются в тестирование сеттеров и геттеров и код типа Assert.AreEqual(2+2, 4). Ну или еще очень модно тестировать всякие "бизнес-методы" типа GetCustomerByID , которые неявно превращаются в тестирование движка БД.
Тестировать нужно бизнеслогику. DAL тестировать не надо
HL>Я уже не говорю, что юнит-тесты значительно усложняют доработки в системе, потому что любая доработка становится ГЕМОРРОЕМ, надо перерабатывать и рефакторить кучу тестов, и value от юнит-тестов начинает асимптотически стремится к нулю. Также юнит-тесты привносят кучу неявных contracts, т.е. любой метод, который я хотел бы скрыть и доработать по мере необходимости, становится "public contract" и на него появляются внешние зависимости.
Если спорадически, как прижмет, то да, это геморрой.
HL>Короче, никакие тесты не сделают из плохого кода хороший и не уменьшат стоимость разработки просто от их наличия. Пишите лучше код, следите за руками, думайте о коде и нанимайте хороших ручных тестировщиков — которые, конечно, должны в коде хотя бы приблизительно разбираться.
Юнит-тесты это инструмент, который позволяет получть информацию о том коде, что ты пишешь. Что ты будешь(умеешь,можешь) делать с этой информацией — вот в чем вопрос.
Здравствуйте, iHateLogins, Вы писали:
HL>Имхо, всё это — естественная реакция. ИТ так далеко шагнуло за последние 10 лет, что, если писать эффективные программы ЭФФЕКТИВНО, толпу всякой около-итной шушеры придётся гнать взашей. Вот они и держутся, как могут. И начинается... простейшие сайтики становятся сложнейшими инжереными проектами с командой поддержки в 20-30 человек, вместо простых селектов в базе накручиваются просто МЕГАТОННЫ всякого водопроводного (plumbing) говно-кода, фреймворки над фреймворками... а дальше начинается... добавить колонку? СЛОЖНЕЙШАЯ ЗАДАЧА! Переработать модуль? Да проще новый написать, желательно даже не модуль, а проект с нуля, потому что разобраться в тоннах запутанного кода с десятками тысяч никому не нужных юнит-тестов становится просто невозможно.
Я немного не понял, что ты имел ввиду про селекты. Как раз накидав всяких селектов получается геморрой — надо добавить колонку таблицу и для этого приходтся перелопачивать селекты.
Здравствуйте, Laurel, Вы писали:
L>Поднимите руки те, у кого возникали хоть когда-нибудь проблемы с методом GetCustomerId.
L>Спасибо.
Пример с GetCustomerId идиотский.
L>А теперь поднимите руки те, кому приходилось писать, а потом поддерживать кучу никому ненужных тестов, проверяющих работоспособность тривиальных методов.
L>Спасибо.
L>Результаты голосования говорят сами за себя.
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, gandjustas, Вы писали:
HL>>>Ты думаешь база данных каким-то волшебным способом сделает из говно-запросов, генеренных l2s, конфетку G>>Совсем не волшебным. Оптимизатор есть.
HL>Какой еще в l2s оптимизатор? Эта шняга тупо проецирует дерево на sql, вообще не догадывается о планах запросов.
Ну-ну, посмотри код l2s.
HL>>>Индексы сама создаст, закэширует что нужно, а что не нужно — не закэширует G>>Индексы ты создашь. HL>Индексы я сам сделаю, план оптимизирую, хинты расставлю... на кой ляд этот l2s нужен-то?
Чтобы запросы делать.
Здравствуйте, _d_m_, Вы писали:
___>Здравствуйте, gandjustas, Вы писали:
G>>>>>>Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
L>>>>>И каким же образом он узнает, что запрос сгенерирован LINQ-ом, а не руками?
G>>>>Никак, а оно ему надо?
___>>>Ну ты же сказал, что SQL запросы от линка гораздо быстрее: т.к. индексы, кэширование в БД, оптимизатор умный. G>>Ссылку.
___>А что по ветке чуть вверх подняться не судьба? ___>http://rsdn.ru/forum/flame.comp/3445983.1.aspx
Читаете через слово?
Вот проведите эксперимент. Напишите сложный linq запрос и его аналог в sql.
G>>У меня был один запрос, который давал SQL примерно на два листа A4, при этом он работал достаточно быстро. G>>Такой запрос я бы просто физически не нарисовал руками, а если бы даже наприсовал, то замучался бы его поддерживать. ___>Я рисую, поддерживаемость отличная.
Мне тебя жаль.
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, gandjustas, Вы писали:
_>>>>>>Это если не особо думать, можно еще нарисовать столько же нюансов.
HL>>>>>Чувак, прикинь, если для проверки GetCustomerByID нужно написать хренову тучу совершенно нетривиальных тестов, сколько же времени придётся убить, чтобы написать что-то более-сложное, чем Hello, World? G>>>>На самом деле только GetCustomerByID в стотыщ раз сложнее, чем hello world.
HL>>>Если у вас GetCustomerByID — это циклопический нетривиальный проект, в 100 000 раз сложнее Hello World, то сайтик с тремя таблицами превратится просто в "Манхэттэнский проект" G>>Ты читать умеешь?
G>>
G>>Для сайтиков с тремя таблицами нужны другие средства.
HL>Ну так ты GetCustomerByID уже превратил в нетривиальный проект, я даже в страшном сне не представлю, во что превратиться проект с 1000 таблицами.
Мда... понимания ноль
Здравствуйте, _d_m_, Вы писали:
___>Ну дак я ему уже так толсто намекал. Хотелось бы узнать природу этого чуда.
Природа этого чуда заключается в двух моментах
1) Генератор l2s знает об особенностях работы оптимизатора сиквела немножко больше среднего программиста. Я неоднократно наблюдал, когда текст запроса обсирался "спецами" по написанию рукопашных, а потом красивый рукопашный скрипт работал медленнее обосранного автоматического.
2) Генератор l2s при динамической сборке запроса может кардинально перекраивать структуру генерируемого скрипта в зависимости от небольших изменений в исходном linq запросе. Руками такое, конечно же, сделать можно, но для этого потребен спец экстра класса, и поддерживаемось этого чуда будет никакой.
Здравствуйте, yuriylsh, Вы писали:
Y> Значит, говоришь, отказ от юнит-тестов делает код живым, развивающимся и легкомодифицируемым?
Если кто то не согласен с тем, что юнит-тесты в массовых количествах это всегда очень хорошо, это совсем не означает, что он утверждает, что юнит-тесты это всегда плохо.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Если кто то не согласен с тем, что юнит-тесты в массовых количествах это всегда очень хорошо, это совсем не означает, что он утверждает, что юнит-тесты это всегда плохо.
Я отвечал на вполне конкретное заявление и iHateLogins вполне однозначно сказал то что сказал. Там не было ничего ни про массовые колличества ни про всегда плохо.
Инструменты на то и нужны, чтобы делать жизнь проще. Если вы сначала стреляете себе в ногу (юнит-тесты), ползёте с черепашьей скоростью, утверждая, что зато "так надёжнее" — то это ваши проблемы и проблемы ваших заказчиков. Рано или поздно они не оценят такой, хм, производительности, и выберут того, кто делает свою работу быстрее. Пусть код не будет покрыт юнит-тестами и API зацементирован этими самыми тестами, зато он будет живой, развивающийся и легкомодифицируемый.
Luck in life always exists in the form of an abstract class that cannot be instantiated directly and needs to be inherited by hard work and dedication.
Здравствуйте, Ikemefula, Вы писали:
HL>>Имхо, всё это — естественная реакция. ИТ так далеко шагнуло за последние 10 лет, что, если писать эффективные программы ЭФФЕКТИВНО, толпу всякой около-итной шушеры придётся гнать взашей. Вот они и держутся, как могут. И начинается... простейшие сайтики становятся сложнейшими инжереными проектами с командой поддержки в 20-30 человек, вместо простых селектов в базе накручиваются просто МЕГАТОННЫ всякого водопроводного (plumbing) говно-кода, фреймворки над фреймворками... а дальше начинается... добавить колонку? СЛОЖНЕЙШАЯ ЗАДАЧА! Переработать модуль? Да проще новый написать, желательно даже не модуль, а проект с нуля, потому что разобраться в тоннах запутанного кода с десятками тысяч никому не нужных юнит-тестов становится просто невозможно.
I>Я немного не понял, что ты имел ввиду про селекты. Как раз накидав всяких селектов получается геморрой — надо добавить колонку таблицу и для этого приходтся перелопачивать селекты.
При добавлении колонки в таблицу все существующие селекты будут работать без проблем, зачем их перелопачивать?
Здравствуйте, Ночной Смотрящий, Вы писали:
L>>Мой опыт показывает, что с тестами скорость разработки увеличивается раза в два. НС>А мой — уменьшается в два раза. Мое имхо против твоего имха?
Референсы будут? У меня — без проблем.
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, _d_m_, Вы писали:
___>>Здравствуйте, gandjustas, Вы писали:
G>>>>>>>Оптимизатор у MS SQL достаточно умный чтобы по запросу сгенерированному с помощью Linq построить хороший план.
L>>>>>>И каким же образом он узнает, что запрос сгенерирован LINQ-ом, а не руками?
G>>>>>Никак, а оно ему надо?
___>>>>Ну ты же сказал, что SQL запросы от линка гораздо быстрее: т.к. индексы, кэширование в БД, оптимизатор умный. G>>>Ссылку.
___>>А что по ветке чуть вверх подняться не судьба? ___>>http://rsdn.ru/forum/flame.comp/3445983.1.aspx
G>Читаете через слово? G>Вот проведите эксперимент. Напишите сложный linq запрос и его аналог в sql.
G>>>У меня был один запрос, который давал SQL примерно на два листа A4, при этом он работал достаточно быстро. G>>>Такой запрос я бы просто физически не нарисовал руками, а если бы даже наприсовал, то замучался бы его поддерживать. ___>>Я рисую, поддерживаемость отличная. G>Мне тебя жаль.
Хм. Май янг френд. Шутка конечно.
Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть.
Хочу такого же на линк:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER proc [dbo].[ОтчетОстаткиТоваров1](
@СкладыУчастникиXML xml,
@НаДату datetime = null,
@Товар char(10) = null,
@ГруппыТоваровXML xml = null,
@ТипУчета tinyint = null,
@флСортПоГруппам bit = 0
)
--# with encryptionas begin
set nocount on;
set transaction isolation level read committed;
-- Обработка параметровif @НаДату is null
set @НаДату = getdate();
-- Получим флаги разрешения просмотра ценdeclare @флРасхЦена tinyint, @флПрихЦена tinyint;
select
@флРасхЦена = флРасхЦена,
@флПрихЦена = флПрихЦена
from
dbo.Пользователи
where
Логин = system_user
;
-- Обработка товаров и группdeclare @ВеткаГруппТоваров table(
Группа char(10) primary key
);
if @Товар is not null
insert
@ВеткаГруппТоваров
select
КодРодителя
from
dbo.пТовары
where
Код = @Товар
;
else if @ГруппыТоваровXML is null
insert
@ВеткаГруппТоваров
select
Код
from
dbo.пТоварыГруппы
;
else
with
РОТВ as(
select
тг.Код
from
dbo.пТоварыГруппы тг
inner join
(select
Гр.value('@Код', 'char(10)') Группа
from
@ГруппыТоваровXML.nodes('/root/Группа') as T(Гр)
) г
on
тг.Код = г.Группа
union all
select
тг1.Код
from
dbo.пТоварыГруппы тг1
inner join
РОТВ в
on
тг1.КодРодителя = в.Код
)
insert
@ВеткаГруппТоваров
select distinct
Код
from
РОТВ
;
-- Обработка складов-участниковdeclare @тСкладыУчастники table(
Склад char(10) primary key
);
insert
@тСкладыУчастники
select
Ск.value('@Код', 'char(10)') Склад
from
@СкладыУчастникиXML.nodes('/root/Склад') as T(Ск)
;
-- Проверка RLSif exists(
select
null
from
@тСкладыУчастники су
where
not exists(
select
null
from
dbo.пСклады as с
where
су.Склад = с.Код
)
) begin
raiserror('Нарушение доступа RLS', 16, 1);
return;
end;
declare @Год int, @Квартал int, @ТочкаРаздела datetime;
set @Год = datepart(year, @НаДату) - 1900;
set @Квартал = datepart(quarter, @НаДату) - 1;
set @ТочкаРаздела = dateadd(quarter, @Квартал + @Год * 4, 0);
set @Квартал = (@Год + 1900) * 4 + @Квартал;
-- Возвращаем результат
-- Получим склады участникиselect
с.Код as Склад_Код,
с.Наименование as Склад
from
@тСкладыУчастники су
inner join
dbo.Склады с
on
су.Склад = с.Код
order by
с.Наименование
;
-- Возвращаем основной результатselect
ДляСорт.Товар_Код,
ДляСорт.Товар,
ДляСорт.ПолныйПутьГруппы,
ДляСорт.Склад_Код,
ДляСорт.Остаток,
dbo.УдобочитаемаяПартия(ДляСорт.ИдТипаДокаПартии, ДляСорт.КодДокаПартии, ДляСорт.НомерПартии, ' ') as Партия,
dbo.ПолучитьБазовуюЕдиницу(ДляСорт.Товар_Код) as Единица,
case @флПрихЦена
when 1 then ДляСорт.Себестоимость
end as Себестоимость,
case @флПрихЦена
when 1 then dbo.ТоварЗакупЦена_NonRLS(ДляСорт.Товар_Код, @НаДату)
end as ПрихЦена,
case @флРасхЦена
when 1 then dbo.ТоварЦена_NonRLS(ДляСорт.Товар_Код, @НаДату, default)
end as ПродЦена,
(select
isnull(sum(Резерв), 0.0)
from
dbo.РезервыТоваров as рт
where
рт.Товар = ДляСорт.Товар_Код and
рт.Склад = ДляСорт.Склад_Код
) as Резерв
from
(select
ТО.Товар_Код,
т.Наименование as Товар,
dbo.ф_ТоварыГруппыПолныйПуть(т.КодРодителя) as ПолныйПутьГруппы,
ТО.Склад_Код,
ТО.Остаток,
ТО.Себестоимость,
ТО.ИдТипаДокаПартии,
ТО.КодДокаПартии,
ТО.НомерПартии
from
(select
isnull(Гпдт.Склад, Гдт.Склад) as Склад_Код,
isnull(Гпдт.Товар, Гдт.Товар) as Товар_Код,
sum(isnull(Гпдт.ДвижениеОстатка, 0.0) + isnull(Гдт.ДвижениеОстатка, 0.0)) as Остаток,
sum(isnull(Гпдт.ДвижениеСебест, 0.0) + isnull(Гдт.ДвижениеСебест, 0.0)) as Себестоимость,
isnull(Гпдт.ИдТипаДокаПартии, Гдт.ИдТипаДокаПартии) as ИдТипаДокаПартии,
isnull(Гпдт.КодДокаПартии, Гдт.КодДокаПартии) as КодДокаПартии,
isnull(Гпдт.НомерПартии, Гдт.НомерПартии) as НомерПартии
from
(select
пдт.Склад,
пдт.Товар,
пдт.ИдТипаДокаПартии,
пдт.КодДокаПартии,
пдт.НомерПартии,
sum(пдт.ДвижениеОстатка) as ДвижениеОстатка,
sum(пдт.ДвижениеСебест) as ДвижениеСебест
from
dbo.пГДвиженияТоваров as пдт with(noexpand)
where
exists(
select
null
from
@тСкладыУчастники с
where
с.Склад = пдт.Склад
) and
exists(
select
null
from
dbo.ТоварыГруппыММ гмм
inner join
@ВеткаГруппТоваров вгт
on
гмм.Группа = вгт.Группа
where
пдт.Товар = гмм.Товар
) and
пдт.Квартал <= @Квартал and
(пдт.Товар = @Товар or @Товар is null)
group by
пдт.Склад,
пдт.Товар,
пдт.ИдТипаДокаПартии,
пдт.КодДокаПартии,
пдт.НомерПартии
) as Гпдт
full outer join
(select
дт.Склад,
дт.Товар,
дт.ИдТипаДокаПартии,
дт.КодДокаПартии,
дт.НомерПартии,
sum(дт.ДвижениеОстатка) as ДвижениеОстатка,
sum(дт.ДвижениеСебест) as ДвижениеСебест
from
dbo.ДвиженияТоваров as дт
where
exists(
select
null
from
@тСкладыУчастники с
where
с.Склад = дт.Склад
) and
exists(
select
null
from
dbo.ТоварыГруппыММ гмм
inner join
@ВеткаГруппТоваров вгт
on
гмм.Группа = вгт.Группа
where
дт.Товар = гмм.Товар
) and
дт.ТочкаВремени >= @ТочкаРаздела and
дт.ТочкаВремени < @НаДату and
(дт.Товар = @Товар or @Товар is null)
group by
дт.Склад,
дт.Товар,
дт.ИдТипаДокаПартии,
дт.КодДокаПартии,
дт.НомерПартии
) as Гдт
on
Гпдт.Товар = Гдт.Товар and
Гпдт.Склад = Гдт.Склад and
Гпдт.ИдТипаДокаПартии = Гдт.ИдТипаДокаПартии and
Гпдт.КодДокаПартии = Гдт.КодДокаПартии and
Гпдт.НомерПартии = Гдт.НомерПартии
group by
isnull(Гпдт.Товар, Гдт.Товар),
isnull(Гпдт.Склад, Гдт.Склад),
isnull(Гпдт.ИдТипаДокаПартии, Гдт.ИдТипаДокаПартии),
isnull(Гпдт.КодДокаПартии, Гдт.КодДокаПартии),
isnull(Гпдт.НомерПартии, Гдт.НомерПартии)
having
sum(isnull(Гпдт.ДвижениеОстатка, 0.0) + isnull(Гдт.ДвижениеОстатка, 0.0)) != 0.0
) as ТО
inner join
dbo.Товары as т
on
ТО.Товар_Код = т.Код
where
т.флУпрУчет = @ТипУчета or @ТипУчета is null
) as ДляСорт
order by
case @флСортПоГруппам
when 1 then rank() over(order by ДляСорт.ПолныйПутьГруппы, ДляСорт.Товар, ДляСорт.Склад_Код)
else rank() over(order by ДляСорт.Товар, ДляСорт.Склад_Код)
end
;
end
GO
GRANT EXECUTE ON [dbo].[ОтчетОстаткиТоваров1] TO [1 ОтчетОстаткиТоваров]
Здравствуйте, _d_m_, Вы писали:
___>Хм. Май янг френд. Шутка конечно. ___>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть.
Не, я не буду sql-, или каким_то_другим- программером. Я стараюсь быть просто программистом, который для решения задач выбирает подходящее средство.
И мне всегда жаль будет sql-, или_еще_каких_то- программеров которые используя неподходящие средства пытаются скрестить ежа с ужом.
___>Хочу такого же на линк:
Опиши по-русски что код делает, а то реверсить такое желания нету.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, _d_m_, Вы писали:
___>>Ну дак я ему уже так толсто намекал. Хотелось бы узнать природу этого чуда.
НС>Природа этого чуда заключается в двух моментах НС>1) Генератор l2s знает об особенностях работы оптимизатора сиквела немножко больше среднего программиста. Я неоднократно наблюдал, когда текст запроса обсирался "спецами" по написанию рукопашных, а потом красивый рукопашный скрипт работал медленнее обосранного автоматического.
Только плюс линку. Но заниматься преждевременной оптимизацией — "красивый рукопашный скрипт" — зло. Запросы надо писать так, как-будто ничего не знаешь про работу движка СУБД. И только если есть проблемы с перфомансом — тогда надо взятся всерьез. Вот тогда рукопашный скрипт становится красивым.
НС>2) Генератор l2s при динамической сборке запроса может кардинально перекраивать структуру генерируемого скрипта в зависимости от небольших изменений в исходном linq запросе. Руками такое, конечно же, сделать можно, но для этого потребен спец экстра класса, и поддерживаемось этого чуда будет никакой.
Классно. Но это хак. Оптимизатор СУБД должен этим заниматься.
PS: Речь изначально шла не об этом. Сначала gandjustas ляпнул ерунду (или коряво выразился), которую всем понять было только как: кэширование и индексы работают только для линк-запросов.
Здравствуйте, gandjustas, Вы писали:
___>>Хм. Май янг френд. Шутка конечно. ___>>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. G>Не, я не буду sql-, или каким_то_другим- программером. Я стараюсь быть просто программистом, который для решения задач выбирает подходящее средство. G>И мне всегда жаль будет sql-, или_еще_каких_то- программеров которые используя неподходящие средства пытаются скрестить ежа с ужом.
На SQL вообще-то все серьёзные ERP системы написаны, а не на C#. Говорю это вам как человек, который программирует на C# со второй беты 1.0 и на SQL уже больше 10 лет. C# — это такой integration язык, на нём хорошо писать "прослойки". Для серьёзной работы с данными человечество не придумал ничего лучше (T|PL)-SQL, для вычислений — ASM/C/C++, для UI всё больше народу выбирает HTML/CSS или "голый" winapi. На C#-е лучше всего писать веб-приложения или какой-то integration layer, но не транзакции. Во всяком случае, не серьёзные транзакции.
___>>Хочу такого же на линк: G>Опиши по-русски что код делает, а то реверсить такое желания нету.
Код-то простой как три копейки, что там реверсить-то?
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, _d_m_, Вы писали:
___>>Хм. Май янг френд. Шутка конечно. ___>>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. G>Не, я не буду sql-, или каким_то_другим- программером. Я стараюсь быть просто программистом, который для решения задач выбирает подходящее средство. G>И мне всегда жаль будет sql-, или_еще_каких_то- программеров которые используя неподходящие средства пытаются скрестить ежа с ужом.
То есть я пытаюсь скрестить ужа с ежом? На каком основании мне навешан этот ярлык?
___>>Хочу такого же на линк: G>Опиши по-русски что код делает, а то реверсить такое желания нету.
Мне тебя жалко Шутка.
Остатки товаров на определнный момент времени получает c фильтром по веткам дерева групп, с фильтром по складам, при необходимости сортирует в группах товаров. Средний слой затем может провести дополнительные группировки и развертки ака pivot. Вобщем это не задача для легковесной ORM ака linq.
Здравствуйте, _d_m_, Вы писали:
НС>>2) Генератор l2s при динамической сборке запроса может кардинально перекраивать структуру генерируемого скрипта в зависимости от небольших изменений в исходном linq запросе. Руками такое, конечно же, сделать можно, но для этого потребен спец экстра класса, и поддерживаемось этого чуда будет никакой.
___>Классно. Но это хак. Оптимизатор СУБД должен этим заниматься.
Ты не понял. В самом языке SQL есть ограничения, делающие его менее выразительным, по сравнению с C#, на котором работает Linq. Поэтому небольшие изменения в Linq погут порождать занчительные измения в sql.
Яркий пример такого — сравнение с null. В sql получается разный текст запроса если надо сравнить с NULL или с конкретным значением, а в linq это пишется одинаково.
___>PS: Речь изначально шла не об этом. Сначала gandjustas ляпнул ерунду (или коряво выразился), которую всем понять было только как: кэширование и индексы работают только для линк-запросов.
Это ты неправльно понял. Я же уже писал выше, что наибольший вклад в производительность запроса обычно вносят индексы. Опитмизатор в MS SQL достаточно умный чтобы сгенеренному linq запросу построить более-менее оптимальный план.
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, gandjustas, Вы писали:
___>>>Хм. Май янг френд. Шутка конечно. ___>>>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. G>>Не, я не буду sql-, или каким_то_другим- программером. Я стараюсь быть просто программистом, который для решения задач выбирает подходящее средство. G>>И мне всегда жаль будет sql-, или_еще_каких_то- программеров которые используя неподходящие средства пытаются скрестить ежа с ужом.
HL>На SQL вообще-то все серьёзные ERP системы написаны, а не на C#. Говорю это вам как человек, который программирует на C# со второй беты 1.0 и на SQL уже больше 10 лет. C# — это такой integration язык, на нём хорошо писать "прослойки". Для серьёзной работы с данными человечество не придумал ничего лучше (T|PL)-SQL, для вычислений — ASM/C/C++, для UI всё больше народу выбирает HTML/CSS или "голый" winapi. На C#-е лучше всего писать веб-приложения или какой-то integration layer, но не транзакции. Во всяком случае, не серьёзные транзакции.
___>>>Хочу такого же на линк: G>>Опиши по-русски что код делает, а то реверсить такое желания нету. HL>Код-то простой как три копейки, что там реверсить-то?
Ну расскажи что он там делает
Здравствуйте, _d_m_, Вы писали: ___>Хм. Май янг френд. Шутка конечно. ___>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. ___>Хочу такого же на линк:
А что мешает? Такое же на линке обычно выглядит гораздо более внятно. И не требует, в частности, массовых манипуляций с временными таблицами.
Что там у вас за ужос с @ВеткаГруппТоваров?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, _d_m_, Вы писали:
___>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, _d_m_, Вы писали:
___>>>Хм. Май янг френд. Шутка конечно. ___>>>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. G>>Не, я не буду sql-, или каким_то_другим- программером. Я стараюсь быть просто программистом, который для решения задач выбирает подходящее средство. G>>И мне всегда жаль будет sql-, или_еще_каких_то- программеров которые используя неподходящие средства пытаются скрестить ежа с ужом. ___>То есть я пытаюсь скрестить ужа с ежом? На каком основании мне навешан этот ярлык?
Нет, я не говорил конкретно про тебя.
Просто подход "я умею писать на SQL, поэтому все будут писать на SQL" неправильный.(вместо SQL можно подставить любой другой язык)
___>>>Хочу такого же на линк: G>>Опиши по-русски что код делает, а то реверсить такое желания нету.
___>Мне тебя жалко Шутка. ___>Остатки товаров на определнный момент времени получает c фильтром по веткам дерева групп, с фильтром по складам, при необходимости сортирует в группах товаров. Средний слой затем может провести дополнительные группировки и развертки ака pivot. Вобщем это не задача для легковесной ORM ака linq.
Ок, судя по описанию так:
var warehouses = //обработка xml с помощью XLinq для вытаскивания складовvar groups = //обработка xml с помощью XLinq для вытаскивания группvar q = from p in db.Products
where warehouses.Contains(p.Warehouse)
where groups.Contains(p.Groups)
select p;
if(/*необходимость*/)
{
q = q.OrderBy(p => p.Group);
}
Далее этот запрос попадает в верхний слой, там проводятся дополнительные группировки, а на уровне PL приводится все в читаемый вид.
Причем пока реально не понадобилось отображать данные, то лучше и не будет этот запрос выполняться.
ЗЫ. А вообще такие вещи лучше делать в OLAP, чтобы он аггрегаты по любым измерениям собирал, а потом быстро отдавал без мега-запросов.
Здравствуйте, gandjustas, Вы писали:
G>Причем пока реально не понадобилось отображать данные, то лучше и не будет этот запрос выполняться.
Выделенное слово попало сюда по ошибке
Здравствуйте, iHateLogins, Вы писали:
I>>Я немного не понял, что ты имел ввиду про селекты. Как раз накидав всяких селектов получается геморрой — надо добавить колонку таблицу и для этого приходтся перелопачивать селекты.
HL>При добавлении колонки в таблицу все существующие селекты будут работать без проблем, зачем их перелопачивать?
А колонку ты зачем добавлял ? Просто что бы в базе побыла ?
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, _d_m_, Вы писали:
НС>>>2) Генератор l2s при динамической сборке запроса может кардинально перекраивать структуру генерируемого скрипта в зависимости от небольших изменений в исходном linq запросе. Руками такое, конечно же, сделать можно, но для этого потребен спец экстра класса, и поддерживаемось этого чуда будет никакой.
___>>Классно. Но это хак. Оптимизатор СУБД должен этим заниматься. G>Ты не понял. В самом языке SQL есть ограничения, делающие его менее выразительным, по сравнению с C#, на котором работает Linq. Поэтому небольшие изменения в Linq погут порождать занчительные измения в sql. G>Яркий пример такого — сравнение с null. В sql получается разный текст запроса если надо сравнить с NULL или с конкретным значением, а в linq это пишется одинаково.
Эээ нет. null — это особая тема. Опять не умеешь готовить. Это не недостаток SQL — это совсем другое.
___>>PS: Речь изначально шла не об этом. Сначала gandjustas ляпнул ерунду (или коряво выразился), которую всем понять было только как: кэширование и индексы работают только для линк-запросов. G>Это ты неправльно понял. Я же уже писал выше, что наибольший вклад в производительность запроса обычно вносят индексы. Опитмизатор в MS SQL достаточно умный чтобы сгенеренному linq запросу построить более-менее оптимальный план.
Я же тебе говорю, что по любому SQL запросу оптимизатор строит самый оптимальный план.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, gandjustas, Вы писали:
G>>Мда... понимания ноль
НС>Любимый аргумент религиозных фанатиков.
начники пишут также, справедливости ради уточню
Здравствуйте, gandjustas, Вы писали:
G>ЗЫ. А вообще такие вещи лучше делать в OLAP, чтобы он аггрегаты по любым измерениям собирал, а потом быстро отдавал без мега-запросов.
Нет. Сферический конь в вакууме здесь не нужен. Это не аналитика продаж в разных проекциях. Это реал-тайм запрос. И он выполняется мгновенно. Потому что нужно знать остаток для покупателя который ждет сейчас и ждать его заствлять нельзя никак.
И это вобще-то ни мега-запрос, как тут уже сказали, запрос прост... Для тех кто в теме.
Здравствуйте, _d_m_, Вы писали: ___>Мне тебя жалко Шутка. ___>Остатки товаров на определнный момент времени получает c фильтром по веткам дерева групп, с фильтром по складам, при необходимости сортирует в группах товаров. Средний слой затем может провести дополнительные группировки и развертки ака pivot. Вобщем это не задача для легковесной ORM ака linq.
Это как раз самая та задача для Linq. То, что у вас там так много кода, вызвано исключительно убогостью TSQL, точнее убогостью его возможностей по декомпозиции.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, iHateLogins, Вы писали:
___>>>Хм. Май янг френд. Шутка конечно. ___>>>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. G>>Не, я не буду sql-, или каким_то_другим- программером. Я стараюсь быть просто программистом, который для решения задач выбирает подходящее средство. G>>И мне всегда жаль будет sql-, или_еще_каких_то- программеров которые используя неподходящие средства пытаются скрестить ежа с ужом.
HL>На SQL вообще-то все серьёзные ERP системы написаны, а не на C#. Говорю это вам как человек, который программирует на C# со второй беты 1.0 и на SQL уже больше 10 лет. C# — это такой integration язык, на нём хорошо писать "прослойки". Для серьёзной работы с данными человечество не придумал ничего лучше (T|PL)-SQL,
Расскажете нам какой хороший T-SQL, когда придет требование от заказчика сменить СУБД с MS SQL на Oracle.
Вы серьезно думаете, что O/RM от нечего делать придумали?..
HL>для вычислений — ASM/C/C++,
Ой, что серьезно чтоли? HL>для UI всё больше народу выбирает HTML/CSS или "голый" winapi.
Этот бред вообще ни в какие ворота не лезет. Много Вы видели интерфейсов на чистом ВинАПИ? Может назовете десяток известных приложений с интерфейсами на "голом" winapi?
То-то последние версии профессиональных продуктов все чаще на WPF написаны оказываются... они наверно чего-то не знали, да? AutoCAD, Visual Studio...
HL>На C#-е лучше всего писать веб-приложения или какой-то integration layer, но не транзакции. Во всяком случае, не серьёзные транзакции.
Это не транзакции несерьезные. Это Ваш профанизм и явное не знание предмета несерьезно.
HL>>>Юнит-тесты уже становятся параноей, в 99% они превращаются в тестирование сеттеров и геттеров и код типа Assert.AreEqual(2+2, 4). L>>Не читал, но осуждаю, да?
L>>Если Вы не умеете их готовить, то это вовсе не значит, что все не умеют.
HL>Да я не осуждаю сами юнит-тесты, идея-то неплохая в общем, и для ряда задач очень нужная. Для парсеров, компиляторов итд. Для ERP-барахла, однако, где, как тут недавно говорили, 2+2 не всегда равно 4, юнит-тесты очень часто оказываются пустой тратой времени. Не всегда, но очень часто.
А Вы не задумывались над тем, что к написанию тестов тоже нужно подходить с умом?
Здравствуйте, neFormal, Вы писали:
L>>Программистам смотреть обязательно, вне зависимости от языка и платформы.
F>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О.
Полезность тестов не надо доказывать. Она очевидна. Особенно, если практиковать методику проектирования, называемую TDD — не поймете пока сами не попробуете на практике.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, _d_m_, Вы писали: ___>>Хм. Май янг френд. Шутка конечно. ___>>Вот когда будешь SQL программером, тогда я посмотрю кто кого будет жалеть. ___>>Хочу такого же на линк: S>А что мешает? Такое же на линке обычно выглядит гораздо более внятно. И не требует, в частности, массовых манипуляций с временными таблицами. S>Что там у вас за ужос с @ВеткаГруппТоваров?
Нет никакого ужОса.
Товар может быть в нескольких группах товара. Таким образом, можно создавать множество классификаторов.
Например:
1. по типу товара: стир. машины, утюги, микроволновки, ...;
2. по производителю: Браун, Аристон, ...
И мы можем отчеты смотреть либо в разрезах типа товара, либо производителя.
И это не все:
Реализована Row Level Security (RLS)- т.е. можно назначить, например, право читать только определнные группы товаров. Таким образом можно назначть читать группу Браун, где есть стир. машины, бритвы и др.
RLS — реализована через представления, поэтому где используется приставка п — пТовары, пСклады и пр. — уже отфильтровано через фильтры RLS.
Манипуляции с временными табличными переменными выявили реальный прирост производительности, по сравнению с включением всего в один запрос. Факт. И точка. Эти манипуляции появились как поздние модификации, так шта...
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, iHateLogins, Вы писали:
I>>>Я немного не понял, что ты имел ввиду про селекты. Как раз накидав всяких селектов получается геморрой — надо добавить колонку таблицу и для этого приходтся перелопачивать селекты.
HL>>При добавлении колонки в таблицу все существующие селекты будут работать без проблем, зачем их перелопачивать?
I>А колонку ты зачем добавлял ? Просто что бы в базе побыла ?
HL>Короче, Шура, пишите, пишите тесты. Только потом не возмущайтесь, добавление колонки в базу стало СВЕРХ-СЛОЖНЫМ ИНЖЕНЕРНЫМ ПРОЕКТОМ.
Вы проекцируете свое незнание/неумение писать тесты на других. Вам стоило бы почитать пару хороших книг по модульному тестированию вместо того, чтоб хаить его, не имея ни малейшего представления о ГРАМОТНОМ модульном тестировании, где НЕ тестируется 2+2=4, где НЕ тестируются СУБД, система ввода-вывода и т.п.
Еще чисто для справки: переход на TDD три года тому назад позволил нам увеличить производительность нашей команды почти в полтора раза и сэкономил массу времени на отладку и ручное тестирование (ручное тестирование конечно же имеет место и не надо думать, что ручное тестирование и модульное тестирование взаимозаменимы).
Здравствуйте, _d_m_, Вы писали:
C>>Расскажете нам какой хороший T-SQL, когда придет требование от заказчика сменить СУБД с MS SQL на Oracle.
___>Смешно.
Не понял что смешного? Подобные переходы от одной СУБД к другой случаются сплошь и рядом.
___>Ладно. От заказчика вам придет требование сменить язык разработки с C# на Ocaml. И?
Заказчику обычно все-равно на каком языке написано, но совсем не все-равно какая СУБД используется.
Здравствуйте, criosray, Вы писали:
C>Здравствуйте, _d_m_, Вы писали:
C>>>Расскажете нам какой хороший T-SQL, когда придет требование от заказчика сменить СУБД с MS SQL на Oracle.
___>>Смешно. C>Не понял что смешного? Подобные переходы от одной СУБД к другой случаются сплошь и рядом.
СУБД не баба — просто так не сменишь.
___>>Ладно. От заказчика вам придет требование сменить язык разработки с C# на Ocaml. И? C>Заказчику обычно все-равно на каком языке написано, но совсем не все-равно какая СУБД используется.
СУБД — да это определяется сразу. А вот перекидывать с одной СУБД на другую — тот еще гемор — заказчик посылается в лес.
А что linq и для Oracle работает?
___>Манипуляции с временными табличными переменными выявили реальный прирост производительности, по сравнению с включением всего в один запрос. Факт. И точка. Эти манипуляции появились как поздние модификации, так шта...
Серъезно что ли? А мне вот кажется, из чтения исходного текста, что "исходный запрос" был в лучшем случае монструозным наворотом всего подряд через IsNull.
Если он вообще был.
Я вот не верю, что для случая @Товар is not null выгоднее запихать всё в промежуточную таблицу и потом обращаться к ней, а не сделать обращение к nТовары напрямую (либо вообще заселектить один раз родителя в переменную); не верю, что фрагмент "where пдт.Товар = @Товар or @Товар is null" выполняется быстрее, чем просто ""where пдт.Товар = @Товар".
Я такие запросы в своей жизни видел. И мотивация там как правило именно такая — убогие возможности T-SQL. Если бы могли — написали бы именно так, как в линке:
if (itemId.HasValue)
q = q.Where(l => l.Item == itemId.Value);
Если ты посмотришь внимательно на те частные случаи, которые обрабатываются этой вашей простыней, то окажется, что для каждого из них можно написать более эффективный запрос. Но это слишком дорого — поддерживать столько эффективных запросов. Остаётся две альтернативы — динамический SQL (он на таких уровнях сложности практически не поддаётся отладке), либо вот такая, как у вас, частичная декомпозиция через табличные переменные.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, _d_m_, Вы писали:
___>Я же тебе говорю, что по любому SQL запросу оптимизатор строит самый оптимальный план.
Это, конечно же, тоже иллюзия.
1. оптимизатор строит оптимальный план исходя из своих знаний о запросе и базе данных.
2. оптимизатор не пытается построить самый оптимальный план. Его задача — по быстрому выбрать более-менее приемлемый план запроса, чтобы цена оптимизации не превысила полученную выгоду.
Упражнение для просветления: сравнить стоимость выполнения этих эквивалентных запросов:
select count(*) from sysobjects
select count(*) from sysobjects where id = isnull(id, id)
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, iHateLogins, Вы писали: HL>При добавлении колонки в таблицу все существующие селекты будут работать без проблем, зачем их перелопачивать?
Да ладно. Прямо таки все?
И даже select distinct * будет работать без изменений?
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, _d_m_, Вы писали:
C>>>>Расскажете нам какой хороший T-SQL, когда придет требование от заказчика сменить СУБД с MS SQL на Oracle.
___>>>Смешно. C>>Не понял что смешного? Подобные переходы от одной СУБД к другой случаются сплошь и рядом.
___>СУБД не баба — просто так не сменишь.
Конечно Вам просто так не сменить — у вас же масса кода на т-эскуэль. Мы же перевели два разных проекта с MS SQL на Oracle ОЧЕНЬ быстро, не переписывая ни строчки кода.
___>>>Ладно. От заказчика вам придет требование сменить язык разработки с C# на Ocaml. И? C>>Заказчику обычно все-равно на каком языке написано, но совсем не все-равно какая СУБД используется.
___>СУБД — да это определяется сразу. А вот перекидывать с одной СУБД на другую — тот еще гемор — заказчик посылается в лес. ___>А что linq и для Oracle работает?
Здравствуйте, _d_m_, Вы писали:
HL>>>При добавлении колонки в таблицу все существующие селекты будут работать без проблем, зачем их перелопачивать?
I>>А колонку ты зачем добавлял ? Просто что бы в базе побыла ?
___>Ну это конкретный слив. Либо с БД не работал.
Я тоже умею говорить про слив.
Объясни, для чего добавляется колонка, если не просто так, чт бы в базе была.
Здравствуйте, criosray, Вы писали:
___>>СУБД не баба — просто так не сменишь. C>Конечно Вам просто так не сменить — у вас же масса кода на т-эскуэль. Мы же перевели два разных проекта с MS SQL на Oracle ОЧЕНЬ быстро, не переписывая ни строчки кода.
Значит вы использовали возможности СУБД, скажем, на 20%. Не больше.
___>>>>Ладно. От заказчика вам придет требование сменить язык разработки с C# на Ocaml. И? C>>>Заказчику обычно все-равно на каком языке написано, но совсем не все-равно какая СУБД используется.
___>>СУБД — да это определяется сразу. А вот перекидывать с одной СУБД на другую — тот еще гемор — заказчик посылается в лес. ___>>А что linq и для Oracle работает?
C>А с каких пор LINQ стал O/RM?
легковесным.
C>NHibernate и EntityFramework — вот это O/RM.
Щаз найдется куча спецов действильно вкушавших устриц ORM — которые скажут, что ORM как таковое зло. Уже была куча флеймов по этому поводу. Приглашаем высказаться http://rsdn.ru/Users/343.aspx.
Здравствуйте, _d_m_, Вы писали: ___>Что конкретно непонятно? Разъясню.
Мне всё как раз понятно. Это был риторический вопрос — то, что вы там делаете, это банальное неумение сиквела выделять "подзапрос" в отдельно определяемую сущность.
То есть вы вручную складываете результаты совершенно различных запросов в таблицу, из которой потом сиквел их достаёт. Таким образом, вы убиваете все возможности по оптимизации результирующего запроса.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, _d_m_, Вы писали:
___>>Манипуляции с временными табличными переменными выявили реальный прирост производительности, по сравнению с включением всего в один запрос. Факт. И точка. Эти манипуляции появились как поздние модификации, так шта... S>Серъезно что ли? А мне вот кажется, из чтения исходного текста, что "исходный запрос" был в лучшем случае монструозным наворотом всего подряд через IsNull. S>Если он вообще был. S>Я вот не верю, что для случая @Товар is not null выгоднее запихать всё в промежуточную таблицу и потом обращаться к ней, а не сделать обращение к nТовары напрямую
Опять, же напомню про RLS. пТовары разворачивается в:
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER view [dbo].[пТовары]
--# with encryptionas
select
т.Код,
т.Наименование,
т.КодРодителя,
case п.флПрихЦена
when 1 then т.н_ЗакупЦена
else null
end as н_ЗакупЦена,
case п.флРасхЦена
when 1 then т.н_Цена
else null
end as н_Цена,
т.РазмерЦенника,
т.СкидкаНаТовар,
т.ОграничениеСкидки,
т.н_Примечание,
т.н_ТипТовара,
т.ВалютаУчета_Код,
т.н_СтранаПроизводитель,
т.СтавкаНДС,
т.флУслуга,
т.флУпрУчет,
т.н_МинОстаток,
т.ИдНабораХарик,
т.ИдНабораПартХарик,
т.ШагДискретностиКолва,
т.Версия
from
dbo.Товары т
inner join
dbo.Пользователи п
on
п.Логин = system_user
where
exists(
select
null
from
dbo.пТоварыГруппыММ_ВС_ТоварыГруппы гммг with(noexpand)
where
гммг.Товар = т.Код and
exists(
select
null
from
dbo.пМаскаПрав_ММ_Пользователи мпп with(noexpand)
where
мпп.Логин = system_user and
мпп.ИмяОбъекта = N'Товары' and
мпп.СкладПрихода is null and
мпп.СкладРасхода is null and (
(мпп.Чтение <> 0 and гммг.Владелец = мпп.Ид) or
(мпп.Чтение = 2 and exists(
select
null
from
dbo.ТоварыГруппыФильтрБезоп as фб
where
фб.Группа = мпп.ГруппаПользователей and
фб.Код = гммг.Группа
))
)
)
)
GO
GRANT SELECT ON [dbo].[пТовары] TO [1 Товары.Чтение]
GO
GRANT SELECT ON [dbo].[пТовары] TO [3 Оператор ККМ]
Ну не из пальца я высосал этот код. Был он и без табличных переменных. Тесты, тесты на реальных данных, это эволюция — итог я выложил.
S>(либо вообще заселектить один раз родителя в переменную);
Может быть несколько родителей.
S>не верю, что фрагмент "where пдт.Товар = @Товар or @Товар is null" выполняется быстрее, чем просто ""where пдт.Товар = @Товар".
Оптимизатор MS SQL умен. И это хавает на ура.
S>Я такие запросы в своей жизни видел. И мотивация там как правило именно такая — убогие возможности T-SQL. Если бы могли — написали бы именно так, как в линке: S>
Да только когда, это начинлось — линка не было даже в зародыше.
S>Если ты посмотришь внимательно на те частные случаи, которые обрабатываются этой вашей простыней, то окажется, что для каждого из них можно написать более эффективный запрос. Но это слишком дорого — поддерживать столько эффективных запросов. Остаётся две альтернативы — динамический SQL (он на таких уровнях сложности практически не поддаётся отладке), либо вот такая, как у вас, частичная декомпозиция через табличные переменные.
Это очень эффективный запрос. Проверено множеством тестом, вариациями, реальными данными и временем. Как я уже упомниал, дальше работает средний слой — дополнительные группировки и развороты навроде pivot. Начальный вариант был проще без материализованных представлений и многих фич, выполнялся еще на SQL 2000.
Здравствуйте, landerhigh, Вы писали:
L>Потому что тема больно общая.
L>Вчера наткнулся на это (вроде не баян). ППКС, так как я сам test infected. Программистам смотреть обязательно, вне зависимости от языка и платформы.
Плохо, отстой. Надо больше сисек!
А вообще креативненько. Чистое подтверждение тому, что если мысль содержит какой-нибудь бред, то надо напечатать её 72-м кеглем, лучше ярко-красным цветом.
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Vladek, Вы писали:
V>Это мужчина или женщина?
Он test-infected!
Я знаю только две бесконечные вещи — Вселенную и человеческую глупость, и я не совсем уверен насчёт Вселенной. (c) А. Эйнштейн
P.S.: Винодельческие провинции — это есть рулез!
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, _d_m_, Вы писали:
___>>Я же тебе говорю, что по любому SQL запросу оптимизатор строит самый оптимальный план. S>Это, конечно же, тоже иллюзия. S>1. оптимизатор строит оптимальный план исходя из своих знаний о запросе и базе данных. S>2. оптимизатор не пытается построить самый оптимальный план. Его задача — по быстрому выбрать более-менее приемлемый план запроса, чтобы цена оптимизации не превысила полученную выгоду.
Зачастую, при попытке строить запрос на основе своих даже немалых знаний и опыта получаем, что простой запрос работает быстрее, т.к. оптимизатор сработал лучше. Преждевременная оптимизамия — ...
S>Упражнение для просветления: сравнить стоимость выполнения этих эквивалентных запросов: S>
S>select count(*) from sysobjects
S>select count(*) from sysobjects where id = isnull(id, id)
S>
Ну это для детей. Для оптимизатора isnull — черный ящик.
Здравствуйте, Ikemefula, Вы писали:
HL>>>>При добавлении колонки в таблицу все существующие селекты будут работать без проблем, зачем их перелопачивать?
I>>>А колонку ты зачем добавлял ? Просто что бы в базе побыла ?
___>>Ну это конкретный слив. Либо с БД не работал.
I>Я тоже умею говорить про слив.
I>Объясни, для чего добавляется колонка, если не просто так, чт бы в базе была.
У тебя могут работать с БД как старые версии клиентов, так и новые версии. Старые клиенты новую колонку и не заметят. Яволь?
Здравствуйте, _d_m_, Вы писали: S>>Я вот не верю, что для случая @Товар is not null выгоднее запихать всё в промежуточную таблицу и потом обращаться к ней, а не сделать обращение к nТовары напрямую ___>Ну не из пальца я высосал этот код. Был он и без табличных переменных. Тесты, тесты на реальных данных, это эволюция — итог я выложил.
И как он выглядел без табличных переменных, позвольте спросить? Был union all из всех трёх источников, или динамика?
S>>не верю, что фрагмент "where пдт.Товар = @Товар or @Товар is null" выполняется быстрее, чем просто ""where пдт.Товар = @Товар". ___>Оптимизатор MS SQL умен. И это хавает на ура.
Правда что ли? Просто в вашем конкретном случае боттлнек не здесь. А в других аналогичных случаях такие выражения запрещают использование определённых индексов.
___>Да только когда, это начинлось — линка не было даже в зародыше.
Но теперь-то он есть! А вы упорно продолжаете считать, что вот эти выпиливания по вазелину лучше, чем он. На самом деле всё строго наоборот — именно такие вещи линк делает эффективнее, чем рукопашные хранимки.
___>Это очень эффективный запрос. Проверено множеством тестом, вариациями, реальными данными и временем.
Я допускаю, что ускорить его еще сильнее уже трудно, а то и невозможно. Для вашего случая реальных данных, естественно.
Но сколько он вам стоил? Вот вы енфорсите один, строго определённый план запроса. А что будет, если селективность отдельных предикатов изменится? Будет ли ваш вариант запроса всё так же "очень эффективен"? Или всё-таки лучше будет иметь набор из восьми запросов, специализированных для каждой комбинации входных параметров, и дать сиквелу оптимизировать их так, как он считает нужным? ___>Как я уже упомниал, дальше работает средний слой — дополнительные группировки и развороты навроде pivot. Начальный вариант был проще без материализованных представлений и многих фич, выполнялся еще на SQL 2000.
И это тоже аргумент в пользу линка — потому что в нём можно легким манием руки сказать "всё, а вот тут дальше пусть работает средний слой". А в вашем случае такие изменения — это пот и слёзы разработчиков и QA.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, _d_m_, Вы писали:
___>>>СУБД не баба — просто так не сменишь. C>>Конечно Вам просто так не сменить — у вас же масса кода на т-эскуэль. Мы же перевели два разных проекта с MS SQL на Oracle ОЧЕНЬ быстро, не переписывая ни строчки кода.
___>Значит вы использовали возможности СУБД, скажем, на 20%. Не больше.
Конечно. Но эти 20% это 100% тех возможностей СУБД, от которых есть прок в нашем случае.
C>>NHibernate и EntityFramework — вот это O/RM.
___>Щаз найдется куча спецов действильно вкушавших устриц ORM — которые скажут, что ORM как таковое зло.
Эти "специалисты" видели ОРМ из далека и не имеют представления о чем говорят.
ОРМ это не серебрянная пуля, но ОРМ гораздо лучше фетиша хранимых процедур в 99% случаев.
К тому же, нормальные ОРМ позволяют мэпить на хранимки и представления, а не только на таблицы.
Вы не поймете этого, пока сами не попробуете этих устриц.
Здравствуйте, _d_m_, Вы писали:
___>>>Ну это конкретный слив. Либо с БД не работал.
I>>Я тоже умею говорить про слив.
I>>Объясни, для чего добавляется колонка, если не просто так, чт бы в базе была.
___>У тебя могут работать с БД как старые версии клиентов, так и новые версии. Старые клиенты новую колонку и не заметят. Яволь?
Еще раз "Объясни, для чего добавляется колонка, если не просто так, чт бы в базе была."
Здравствуйте, criosray, Вы писали:
F>>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О. C>Полезность тестов не надо доказывать. Она очевидна. Особенно, если практиковать методику проектирования, называемую TDD — не поймете пока сами не попробуете на практике.
ты не поймёшь пользы религии пока сам не начнёшь ходить в церковь и молиться..
F>>>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О. C>>Полезность тестов не надо доказывать. Она очевидна. Особенно, если практиковать методику проектирования, называемую TDD — не поймете пока сами не попробуете на практике.
F>ты не поймёшь пользы религии пока сам не начнёшь ходить в церковь и молиться..
Неприятие того, чего Вы не знаете/не понимаете это тоже своего рода религия. Только в отличии от Вас я знаю и понимаю какие плюсы и минусы у TDD. Вы этого не знаете, но слепо верите в то, что сами себе придумали.
Здравствуйте, criosray, Вы писали:
C>>>>>Расскажете нам какой хороший T-SQL, когда придет требование от заказчика сменить СУБД с MS SQL на Oracle.
___>>>>Смешно. C>>>Не понял что смешного? Подобные переходы от одной СУБД к другой случаются сплошь и рядом.
___>>СУБД не баба — просто так не сменишь. C>Конечно Вам просто так не сменить — у вас же масса кода на т-эскуэль. Мы же перевели два разных проекта с MS SQL на Oracle ОЧЕНЬ быстро, не переписывая ни строчки кода.
Стало быть ни mssql-specific типов, функций, системных процедур, индексов, индексированных вьюх, схем, репликации, clr-интеграции, transaction-handling-а, различных уровней изоляции, stored procs, TVF, итд итд итд итд вы не использовали?
В чём смысл переводить проект с одной БД на другую если вы практически не используете возможности самой БД?
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, _d_m_, Вы писали: ___>>Что конкретно непонятно? Разъясню. S>Мне всё как раз понятно. Это был риторический вопрос — то, что вы там делаете, это банальное неумение сиквела выделять "подзапрос" в отдельно определяемую сущность. S>То есть вы вручную складываете результаты совершенно различных запросов в таблицу, из которой потом сиквел их достаёт. Таким образом, вы убиваете все возможности по оптимизации результирующего запроса.
Такой подход как у _d_m_ будет как раз самым быстрым.
Здравствуйте, minorlogic, Вы писали:
HL>>Чувак, прикинь, если для проверки GetCustomerByID нужно написать хренову тучу совершенно нетривиальных тестов, сколько же времени придётся убить, чтобы написать что-то более-сложное, чем Hello, World? Так можно и простейших сайтик с тремя таблицами превратить в многомиллионный проект с гигантской командой разработки (и тестирования).
M>Дык елы палы , так деньги то и зарабатываются
Да знаю я. Еще проще зарабатываются деньги, когда деньги на сайтик выделили, а сайтика вообще нет. Зато отчёт есть.
Здравствуйте, criosray, Вы писали:
HL>>Короче, Шура, пишите, пишите тесты. Только потом не возмущайтесь, добавление колонки в базу стало СВЕРХ-СЛОЖНЫМ ИНЖЕНЕРНЫМ ПРОЕКТОМ.
C>Вы проекцируете свое незнание/неумение писать тесты на других. Вам стоило бы почитать пару хороших книг по модульному тестированию вместо того, чтоб хаить его, не имея ни малейшего представления о ГРАМОТНОМ модульном тестировании, где НЕ тестируется 2+2=4, где НЕ тестируются СУБД, система ввода-вывода и т.п.
Когда кончаются аргументы, начинаются личные оскорбления. Прощайте, сударь, мне с вами спорить неохота.
Здравствуйте, Ikemefula, Вы писали:
I>>>Я немного не понял, что ты имел ввиду про селекты. Как раз накидав всяких селектов получается геморрой — надо добавить колонку таблицу и для этого приходтся перелопачивать селекты. HL>>При добавлении колонки в таблицу все существующие селекты будут работать без проблем, зачем их перелопачивать?
I>А колонку ты зачем добавлял ? Просто что бы в базе побыла ?
надо добавить колонку таблицу и для этого приходтся перелопачивать селекты
Утверждение неверно, т.к. при добавлении колонки в базу селекты перелопачивать не нужно. Если тебе нужно выбрать колонку в каких-то конкретных селектах, то модифицируй селекты. Если ты выбираешь по-умолчанию все колонки в базе, юзай "select *".
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, iHateLogins, Вы писали: HL>>При добавлении колонки в таблицу все существующие селекты будут работать без проблем, зачем их перелопачивать? S>Да ладно. Прямо таки все? S>И даже select distinct * будет работать без изменений?
Понятно, что всё можно извратить и сломать. Если какой-то код использует "select *" для вставки в какую-то таблицу, он свалится. Мораль: селекты селектами, а думать всё-таки нужно. Хотя бы иногда.
Здравствуйте, iHateLogins, Вы писали:
HL>Утверждение неверно, т.к. при добавлении колонки в базу селекты перелопачивать не нужно. Если тебе нужно выбрать колонку в каких-то конкретных селектах, то модифицируй селекты. Если ты выбираешь по-умолчанию все колонки в базе, юзай "select *".
Это из серии вредные советы? Вы в курсе на сколько select * работает медленнее, чем select <перечень полей> ?
Здравствуйте, criosray, Вы писали:
HL>>Утверждение неверно, т.к. при добавлении колонки в базу селекты перелопачивать не нужно. Если тебе нужно выбрать колонку в каких-то конкретных селектах, то модифицируй селекты. Если ты выбираешь по-умолчанию все колонки в базе, юзай "select *".
C>Это из серии вредные советы? Вы в курсе на сколько select * работает медленнее, чем select <перечень полей> ?
Нет, не в курсе . Потому что это не так! Стоимость select * из таблицы практически не зависит от набора полей, если нет специально оптмизированного индекса для этого набора полей. Поэксперементируй как-нибудь самостоятельно, а сюда отпиши результаты.
Я подозревал, что народ в целом не шарит базы данных, но чтобы настолько.
Здравствуйте, criosray, Вы писали:
F>>>>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О. C>>>Полезность тестов не надо доказывать. Она очевидна. Особенно, если практиковать методику проектирования, называемую TDD — не поймете пока сами не попробуете на практике. F>>ты не поймёшь пользы религии пока сам не начнёшь ходить в церковь и молиться.. C>Неприятие того, чего Вы не знаете/не понимаете это тоже своего рода религия. Только в отличии от Вас я знаю и понимаю какие плюсы и минусы у TDD. Вы этого не знаете, но слепо верите в то, что сами себе придумали.
бгг
я этого не говорил, значит кто то только что себе это придумал
Здравствуйте, iHateLogins, Вы писали:
C>>>>>>Расскажете нам какой хороший T-SQL, когда придет требование от заказчика сменить СУБД с MS SQL на Oracle.
___>>>>>Смешно. C>>>>Не понял что смешного? Подобные переходы от одной СУБД к другой случаются сплошь и рядом.
___>>>СУБД не баба — просто так не сменишь. C>>Конечно Вам просто так не сменить — у вас же масса кода на т-эскуэль. Мы же перевели два разных проекта с MS SQL на Oracle ОЧЕНЬ быстро, не переписывая ни строчки кода.
HL>Стало быть ни mssql-specific типов,
O/RM HL>функций, системных процедур,
Зачем? HL>индексов,
Что Вы собрались делать с индексами на клиенте? HL>индексированных вьюх,
O/RM HL>схем,
Схем? Вы что перечисляете на обум все известные Вам термины? O/RM мэпит схему на объектную модель. HL>репликации, clr-интеграции, transaction-handling-а, различных уровней изоляции, stored procs, TVF, итд итд итд итд вы не использовали?
Да откройте для себя наконец O/RM. И transaction handling и мэпинг на таблицы/представления/хранимые процедуры — все выполняется средствами O/RM, позволяя абстрагироваться от конкректной СУБД.
HL>В чём смысл переводить проект с одной БД на другую если вы практически не используете возможности самой БД?
Молодой человек, мы используем возможности самой БД ровно на столько, на сколько того требуют задачи проекта.
Здравствуйте, neFormal, Вы писали:
F>>>>>если надо столько времени доказывать полезность тестов, значит с идеей тестирования не всё в порядке.. //К.О. C>>>>Полезность тестов не надо доказывать. Она очевидна. Особенно, если практиковать методику проектирования, называемую TDD — не поймете пока сами не попробуете на практике. F>>>ты не поймёшь пользы религии пока сам не начнёшь ходить в церковь и молиться.. C>>Неприятие того, чего Вы не знаете/не понимаете это тоже своего рода религия. Только в отличии от Вас я знаю и понимаю какие плюсы и минусы у TDD. Вы этого не знаете, но слепо верите в то, что сами себе придумали.
F>бгг F>я этого не говорил, значит кто то только что себе это придумал
Ну да, Вы именно это и говорили.
HL>>>Утверждение неверно, т.к. при добавлении колонки в базу селекты перелопачивать не нужно. Если тебе нужно выбрать колонку в каких-то конкретных селектах, то модифицируй селекты. Если ты выбираешь по-умолчанию все колонки в базе, юзай "select *".
C>>Это из серии вредные советы? Вы в курсе на сколько select * работает медленнее, чем select <перечень полей> ?
HL>Нет, не в курсе . Потому что это не так! Стоимость select * из таблицы практически не зависит от набора полей, если нет специально оптмизированного индекса для этого набора полей. Поэксперементируй как-нибудь самостоятельно, а сюда отпиши результаты.
Да индекс то тут при чем? Спросите любого вменяемого dba или банально погуглите, чтоб узнать стоимость select *.
HL>Я подозревал, что народ в целом не шарит базы данных, но чтобы настолько.
Да, мы уже заметили, что Вы в базах "не бум-бум".
Здравствуйте, iHateLogins, Вы писали:
___>>>Что конкретно непонятно? Разъясню. S>>Мне всё как раз понятно. Это был риторический вопрос — то, что вы там делаете, это банальное неумение сиквела выделять "подзапрос" в отдельно определяемую сущность. S>>То есть вы вручную складываете результаты совершенно различных запросов в таблицу, из которой потом сиквел их достаёт. Таким образом, вы убиваете все возможности по оптимизации результирующего запроса.
HL>Такой подход как у _d_m_ будет как раз самым быстрым.
Да уж... если уже писать глупости, так по полной не зная меры?
надо добавить колонку таблицу и для этого приходтся перелопачивать селекты
HL>Утверждение неверно, т.к. при добавлении колонки в базу селекты перелопачивать не нужно.
Вообще, если тебе нравится воевать с мельницами могу дать пару аргументов, когда добавление колонки в базу вынудит переписывать селекты.
Если тебе нужно выбрать колонку в каких-то конкретных селектах, то модифицируй селекты. Если ты выбираешь по-умолчанию все колонки в базе, юзай "select *".
Да в том то и дело, чт надо взять и выбрать колонку в конкретных селектах. Просто так, в своём уме, колонки никто не добавляет.
Например придется сджойнить чегонить, в итоге, опаньки, отвалится DAL. Кое какие тесты здесь все таки нужно прогонять.
Здравствуйте, criosray, Вы писали:
C>>>Это из серии вредные советы? Вы в курсе на сколько select * работает медленнее, чем select <перечень полей> ? HL>>Нет, не в курсе . Потому что это не так! Стоимость select * из таблицы практически не зависит от набора полей, если нет специально оптмизированного индекса для этого набора полей. Поэксперементируй как-нибудь самостоятельно, а сюда отпиши результаты.
C>Да индекс то тут при чем? Спросите любого вменяемого dba или банально погуглите, чтоб узнать стоимость select *.
Спросите, пугуглите. Дети малые, блин! Смотри сюды и не позорься:
Берём только 2 колонки из БД (AdventureWorks2008):
А теперь "select *" (все колонки):
Ну что, боец, съел? Разница будет только в скорости передачм по сети, что, например, для 1Gbe или 10Gbe практически не влияет на производительность сервера.
C>>>>Это из серии вредные советы? Вы в курсе на сколько select * работает медленнее, чем select <перечень полей> ? HL>>>Нет, не в курсе . Потому что это не так! Стоимость select * из таблицы практически не зависит от набора полей, если нет специально оптмизированного индекса для этого набора полей. Поэксперементируй как-нибудь самостоятельно, а сюда отпиши результаты.
C>>Да индекс то тут при чем? Спросите любого вменяемого dba или банально погуглите, чтоб узнать стоимость select *.
HL>Спросите, пугуглите. Дети малые, блин! Смотри сюды и не позорься:
Да куда уж мне... на фоне Вас сложно опозориться — не заметит никто.
HL>Берём только 2 колонки из БД (AdventureWorks2008):
HL>
HL>А теперь "select *" (все колонки):
И где тут select *? Тут select <явный перечень полей>
Вот уж опозорились, так опозорились...
HL>
HL>Ну что, боец, съел? Разница будет только в скорости передачм по сети, что, например, для 1Gbe или 10Gbe практически не влияет на производительность сервера.
Передача по сети тут совершенно ни при чем.
Вы в БД явно ничего не понимаете. Как Вы думаете что происходит когда от клиента приходит select *? Сервер парсит запрос, составляет перечень таблиц и представлений откуда производится выборка, потом дергает системные таблицы, чтоб получить полный перечень полей в этих таблицах. Теперь представьте, что таких запросов не 1, ни 2, а тысяча в секунду. Представили?
HL>Учите матчасть!
Вот-вот. Учите.
Здравствуйте, iHateLogins, Вы писали:
HL>>>А теперь "select *" (все колонки): C>>И где тут select *? Тут select <явный перечень полей>
HL>Смотрим:
HL>
HL>Стоимость ТА ЖЕ!
Речь не о стоимости выполнения такого запроса. Речь о стоимости парсинга. У Вас проблемы с пониманием элементарного?
Здравствуйте, criosray, Вы писали:
HL>>Ну что, боец, съел? Разница будет только в скорости передачм по сети, что, например, для 1Gbe или 10Gbe практически не влияет на производительность сервера. C>Передача по сети тут совершенно ни при чем. C>Вы в БД явно ничего не понимаете. Как Вы думаете что происходит когда от клиента приходит select *? Сервер парсит запрос, составляет перечень таблиц и представлений откуда производится выборка, потом дергает системные таблицы, чтоб получить полный перечень полей в этих таблицах. Теперь представьте, что таких запросов не 1, ни 2, а тысяча в секунду. Представили?
Сервер не такой тупой и знает, когда колонки добавились, а когда нет. И уж поверьте, сервер не лезет в таблицы с метаданными для одинаковых запросов, там всё довольно хорошо кэшируется. Поэтому никакой, абсолютно никакой разницы в стоимости запросов, использующих select *, и тот же самый набор полей, нет. По крайней мере в SQL Server.
Здравствуйте, criosray, Вы писали:
C>Речь не о стоимости выполнения такого запроса. Речь о стоимости парсинга. У Вас проблемы с пониманием элементарного?
SQL Server для одинаковых запросов использует довольно неплохой кэш планов, поэтому парсинг запроса производится тогда, когда это нужно и когда плана нет.
Когда нет плана, select * приводит к просмотру метаданных, а явное указание колонок также приводит к просмотру метаданных и статистики (что значительно, кстати, дороже, чем метаданные), чтобы определить
1) наличие индексов
2) наличие FK
3) типы полей
4) много чего еще.
Короче, всё там сделано по-уму в плане кэша запросов, по крайне мере для тех примитивнейших вариантов, что я привёл.
Здравствуйте, iHateLogins, Вы писали:
HL>>>Ну что, боец, съел? Разница будет только в скорости передачм по сети, что, например, для 1Gbe или 10Gbe практически не влияет на производительность сервера. C>>Передача по сети тут совершенно ни при чем. C>>Вы в БД явно ничего не понимаете. Как Вы думаете что происходит когда от клиента приходит select *? Сервер парсит запрос, составляет перечень таблиц и представлений откуда производится выборка, потом дергает системные таблицы, чтоб получить полный перечень полей в этих таблицах. Теперь представьте, что таких запросов не 1, ни 2, а тысяча в секунду. Представили?
HL>Сервер не такой тупой и знает, когда колонки добавились, а когда нет.
Сервер ни черта не знает. Вся информация о схеме хранится в системных таблицах и чтоб составить список полей для выборки сервер будет вынужден выполнить дополнительный запрос в системные таблицы.
HL>И уж поверьте, сервер не лезет в таблицы с метаданными для одинаковых запросов, там всё довольно хорошо кэшируется.
За каждый промах кеша Вам придется платить. Вот и все.
HL>Поэтому никакой, абсолютно никакой разницы в стоимости запросов, использующих select *, и тот же самый набор полей, нет. По крайней мере в SQL Server.
Ну, молодой человек, что я могу сказать... Невеженство — Ваше блаженство.
Здравствуйте, _d_m_, Вы писали:
___>Эээ нет. null — это особая тема. Опять не умеешь готовить. Это не недостаток SQL — это совсем другое.
"особая тема" это и есть недостаток. Почсему для Linq нету такого количества особых тем?
Тебе стоит научиться готовить что-либо за пределами SQL, чтобы понимать различия.
Собственно я это и иимел ввиду когда писал пр оподходящие средства разработки.
___>Я же тебе говорю, что по любому SQL запросу оптимизатор строит самый оптимальный план.
Во-первых не самый оптимальный. Во-вторых при этом условии нету смысла говорить что с помощью linq получаются плохие запросы. Именно с этого и началось
___>И это вобще-то ни мега-запрос, как тут уже сказали, запрос прост... Для тех кто в теме.
Он может и прост, но выглядит довольно монструозно. А это само по себе плохо. Насколько я понимаю, linq создавался в том числе и для того, чтобы запросы выглядели не столь монстряче.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, criosray, Вы писали:
HL>>>>Ну что, боец, съел? Разница будет только в скорости передачм по сети, что, например, для 1Gbe или 10Gbe практически не влияет на производительность сервера. C>>>Передача по сети тут совершенно ни при чем. C>>>Вы в БД явно ничего не понимаете. Как Вы думаете что происходит когда от клиента приходит select *? Сервер парсит запрос, составляет перечень таблиц и представлений откуда производится выборка, потом дергает системные таблицы, чтоб получить полный перечень полей в этих таблицах. Теперь представьте, что таких запросов не 1, ни 2, а тысяча в секунду. Представили?
HL>>Сервер не такой тупой и знает, когда колонки добавились, а когда нет. C>Сервер ни черта не знает. Вся информация о схеме хранится в системных таблицах и чтоб составить список полей для выборки сервер будет вынужден выполнить дополнительный запрос в системные таблицы.
Только если колонки были добавлены/удалены/изменены с момента прошлого аналогичного запроса.
HL>>И уж поверьте, сервер не лезет в таблицы с метаданными для одинаковых запросов, там всё довольно хорошо кэшируется. C>За каждый промах кеша Вам придется платить. Вот и все.
Какой промах? План для "select *" ляжет в кэш планов и будет использован для всех аналогичных запросов. После этого Metadata lookup-а не будет.
Даже для запросов, для которых плана нет, разница в "select *" и "select список полей" практически отсутствует, потому что и там и там будет просмотр метаданных и кучи еще чего.
Здравствуйте, criosray, Вы писали:
___>>>>СУБД не баба — просто так не сменишь. C>>>Конечно Вам просто так не сменить — у вас же масса кода на т-эскуэль. Мы же перевели два разных проекта с MS SQL на Oracle ОЧЕНЬ быстро, не переписывая ни строчки кода.
HL>>Стало быть ни mssql-specific типов, C>O/RM
Что будем делать с типами, отсутствующими в одной БД и присутствующими в другой? С вычисляемыми колонками? HL>>функций, системных процедур, C>Зачем?
Например, чтобы запросы выполнялись быстрее и не было roundtrip-а до клиента.
HL>>индексов, C>Что Вы собрались делать с индексами на клиенте?
На сервере!
HL>>индексированных вьюх, C>O/RM
Интересно, каким образом O/RM решает проблему с материализованными вьюхами? Слышали про такие?
HL>>схем, C>Схем? Вы что перечисляете на обум все известные Вам термины? O/RM мэпит схему на объектную модель. HL>>репликации, clr-интеграции, transaction-handling-а, различных уровней изоляции, stored procs, TVF, итд итд итд итд вы не использовали? C>Да откройте для себя наконец O/RM. И transaction handling и мэпинг на таблицы/представления/хранимые процедуры — все выполняется средствами O/RM, позволяя абстрагироваться от конкректной СУБД.
А вьюхи, процедуры и таблицы кто будет переписывать, если они использует возможности конкретной БД?
HL>>В чём смысл переводить проект с одной БД на другую если вы практически не используете возможности самой БД? C>Молодой человек, мы используем возможности самой БД ровно на столько, на сколько того требуют задачи проекта.
Ну если вы "легко" переводите код с mssql на оракл, рискну предположить, что у вас нет миллионных таблиц, крайне неэффективная схема, в связи с чем заказчик решил "залить" проблему с производительностью деньгами и в приказном порядке заставил переводить всё на оракл.
Здравствуйте, criosray, Вы писали:
___>>>>Что конкретно непонятно? Разъясню. S>>>Мне всё как раз понятно. Это был риторический вопрос — то, что вы там делаете, это банальное неумение сиквела выделять "подзапрос" в отдельно определяемую сущность. S>>>То есть вы вручную складываете результаты совершенно различных запросов в таблицу, из которой потом сиквел их достаёт. Таким образом, вы убиваете все возможности по оптимизации результирующего запроса.
HL>>Такой подход как у _d_m_ будет как раз самым быстрым.
C>Да уж... если уже писать глупости, так по полной не зная меры?
Такое впечатление, что отвечал робот. У тебя там список стандартных ответов что-ли?
Здравствуйте, Eugeny__, Вы писали:
___>>И это вобще-то ни мега-запрос, как тут уже сказали, запрос прост... Для тех кто в теме.
E__>Он может и прост, но выглядит довольно монструозно. А это само по себе плохо. Насколько я понимаю, linq создавался в том числе и для того, чтобы запросы выглядели не столь монстряче.
Может это от того, что вы просто не знаете t-sql?
А то можно и про какой-нибудь (условно) итальйнский (испанский, венгерский) язык сказать, что выглядит монстуозно, какие-то буковки непонятные и слова неизвестные.
HL>>>И уж поверьте, сервер не лезет в таблицы с метаданными для одинаковых запросов, там всё довольно хорошо кэшируется. C>>За каждый промах кеша Вам придется платить. Вот и все.
HL>Какой промах? План для "select *" ляжет в кэш планов и будет использован для всех аналогичных запросов. После этого Metadata lookup-а не будет.
До того, как он ляжет в кеш планов и случится промах. Кроме того, кеш планов имеет такое ствойство как expiration date.
HL>Даже для запросов, для которых плана нет, разница в "select *" и "select список полей" практически отсутствует, потому что и там и там будет просмотр метаданных и кучи еще чего.
Продолжайте в это верить. А лучше почитайте статьи и не пишите больше глупостей.
Например, это http://charlesconradvaz.wordpress.com/2005/07/29/simple-sql-server-performance-tips-2/
Здравствуйте, iHateLogins, Вы писали:
C>>>>Конечно Вам просто так не сменить — у вас же масса кода на т-эскуэль. Мы же перевели два разных проекта с MS SQL на Oracle ОЧЕНЬ быстро, не переписывая ни строчки кода.
HL>>>Стало быть ни mssql-specific типов, C>>O/RM
HL>Что будем делать с типами, отсутствующими в одной БД и присутствующими в другой?
Ничего не будет. O/RM как мэпило, так и будет мэпить. Вам то в любом случае придется заменить отсутствующий тип на максимально близкий аналог из другой СУБД. О мэпинге же позаботится O/RM.
HL>С вычисляемыми колонками?
Не пользуемся и Вам не советуем, но даже в таком случае достаточно поправить мэпинг и хайбернейт (или другая орм тулза) сама будет вычислять значения при загрузке сущности в сессию.
Код не поменяется.
HL>>>функций, системных процедур, C>>Зачем? HL>Например, чтобы запросы выполнялись быстрее и не было roundtrip-а до клиента.
Какая взаимосвязь между "системными процедурами" и тем, что Вы ответили?
HL>>>индексов, C>>Что Вы собрались делать с индексами на клиенте? HL>На сервере!
Ну и какое отношение индексы на сервере имеют к клиентским запросам, кроме того, что сервер их неявно для клиента использует для ускорения поиска? Вы опять ляпнули, не подумав?
HL>>>индексированных вьюх, C>>O/RM
HL>Интересно, каким образом O/RM решает проблему с материализованными вьюхами? Слышали про такие?
Про такие слышал (и не только слышал — у нас в схеме на текущем проекте более десятка таких), а вот про "проблему" не слышал. Расскажите что за проблема такая?
HL>>>схем, C>>Схем? Вы что перечисляете на обум все известные Вам термины? O/RM мэпит схему на объектную модель. HL>>>репликации, clr-интеграции, transaction-handling-а, различных уровней изоляции, stored procs, TVF, итд итд итд итд вы не использовали? C>>Да откройте для себя наконец O/RM. И transaction handling и мэпинг на таблицы/представления/хранимые процедуры — все выполняется средствами O/RM, позволяя абстрагироваться от конкректной СУБД. HL>А вьюхи, процедуры и таблицы кто будет переписывать, если они использует возможности конкретной БД?
dba очевидно. К чему вопрос-то?
HL>>>В чём смысл переводить проект с одной БД на другую если вы практически не используете возможности самой БД? C>>Молодой человек, мы используем возможности самой БД ровно на столько, на сколько того требуют задачи проекта.
HL>Ну если вы "легко" переводите код с mssql на оракл, рискну предположить, что у вас нет миллионных таблиц,
Не знаю что подразумевается под "миллионная таблица", но продакшн база на данный момент представляет собой схему из порядка 800 таблиц с суммарным количеством хранимых сущностей порядка 70 млн.
HL>крайне неэффективная схема,
Это Вам кто такую глупость сказал?
HL>в связи с чем заказчик решил "залить" проблему с производительностью деньгами и в приказном порядке заставил переводить всё на оракл.
Вы Кашпировский? Скажем прямо с экстрасенсорикой у Вас явные проблемы. А перевод базы на Оракл никак не связан с производительностью (которой, кстати, хватало с большим запасом). Старайтесь лучше в следующий раз.
___>>>И это вобще-то ни мега-запрос, как тут уже сказали, запрос прост... Для тех кто в теме.
E__>>Он может и прост, но выглядит довольно монструозно. А это само по себе плохо. Насколько я понимаю, linq создавался в том числе и для того, чтобы запросы выглядели не столь монстряче.
HL>Может это от того, что вы просто не знаете t-sql?
Нет, это от того, что вы не знаете ничего кроме t-sql (да и t-sql знаете ли Вы t-sql?).
HL>А то можно и про какой-нибудь (условно) итальйнский (испанский, венгерский) язык сказать, что выглядит монстуозно, какие-то буковки непонятные и слова неизвестные.
HL>Те кто в теме запрос понимают за 30 секунд.
А что так долго-то? 30 мс не больше. Подумаешь, запрос на 5 страниц со множеством вложенных подзапросов, на который явно угробили десятки человеко-часов.
Я так понял, что "очень просто сменить СУБД" для вас — это переложить все проблемы на "другого парня", который у вас фигурирует под кличкой "dba". Да, при мало-мальски грамотном дизайне приложение должно быть изолировано от хранилища, и, соответственно, смена последнего не должна приводить к изменению кода приложения. Но каким образом из этого утверждения делается вывод, что сменить СУБД легко?
Явно в проекте с базой на 70 млн. сущностей запросы ОРМ не стоит позволять генерить, и объемы кода в итоге, которые необходимо переносить, немаленькие. А сам апликейшин при нормальном дизайне не должен зависеть от базы, вообще независимо от того, ОРМ у вас там или не ОРМ.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Я так понял, что "очень просто сменить СУБД" для вас — это переложить все проблемы на "другого парня", который у вас фигурирует под кличкой "dba".
Вы ничего не путаете? Вы представляете сколько работы будет у dba, если придется не только схему чуть поправить, но и переписать всю тьму кода с tsql на pl/sql?
Как раз в нашем случае dba получает минимум головной боли, т.к. БД выступает в роли простого хранилища данных, а все бизнес логика в дотнет клиенте.
ВВ>Да, при мало-мальски грамотном дизайне приложение должно быть изолировано от хранилища, и, соответственно, смена последнего не должна приводить к изменению кода приложения. Но каким образом из этого утверждения делается вывод, что сменить СУБД легко?
Вы внимательно читали? Г-н iHateLogins предлагал всю бизнес логику запихнуть в хранимки на tsql или pl/sql, а дотнет клиент использовать в качестве непонятно чего ("прослойка" или как он там выразился...).
ВВ>Явно в проекте с базой на 70 млн. сущностей запросы ОРМ не стоит позволять генерить,
С какой это радости? ВВ>и объемы кода в итоге, которые необходимо переносить, немаленькие. А сам апликейшин при нормальном дизайне не должен зависеть от базы, вообще независимо от того, ОРМ у вас там или не ОРМ.
Еще раз ЧИТАЙТЕ внимательно.
Здравствуйте, criosray, Вы писали:
ВВ>>Я так понял, что "очень просто сменить СУБД" для вас — это переложить все проблемы на "другого парня", который у вас фигурирует под кличкой "dba". C>Вы ничего не путаете? Вы представляете сколько работы будет у dba, если придется не только схему чуть поправить, но и переписать всю тьму кода с tsql на pl/sql? C>Как раз в нашем случае dba получает минимум головной боли, т.к. БД выступает в роли простого хранилища данных, а все бизнес логика в дотнет клиенте.
У вас видимо "тьма кода с tsql" ассоциируется исключительно с бизнес-логикой. Сочувствую, ибо это однозначно говорит о качестве ваших проектов.
ВВ>>Явно в проекте с базой на 70 млн. сущностей запросы ОРМ не стоит позволять генерить, C>С какой это радости?
А, ну вы видимо считаете, что всегда можно довериться тому говну, которое генерит NHibernate, а DBA у вас будет тупо таблички перерисовывать. Такой способ бесспорно рулит, если три человека с приложением работают.
Тут и правда без разницы — Оракл или Сиквел сервер.
Обычно вообще-то переход, скажем, на 10g превращается в масштабный и сложный проект и вовсе не потому, что там "бизнес-логика" в базе.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>>>Я так понял, что "очень просто сменить СУБД" для вас — это переложить все проблемы на "другого парня", который у вас фигурирует под кличкой "dba". C>>Вы ничего не путаете? Вы представляете сколько работы будет у dba, если придется не только схему чуть поправить, но и переписать всю тьму кода с tsql на pl/sql? C>>Как раз в нашем случае dba получает минимум головной боли, т.к. БД выступает в роли простого хранилища данных, а все бизнес логика в дотнет клиенте.
ВВ>У вас видимо "тьма кода с tsql" ассоциируется исключительно с бизнес-логикой. Сочувствую, ибо это однозначно говорит о качестве ваших проектов.
Скорее это однозначно говорит о Вашем полном непонимании предмета спора.
ВВ>>>Явно в проекте с базой на 70 млн. сущностей запросы ОРМ не стоит позволять генерить, C>>С какой это радости?
ВВ>А, ну вы видимо считаете, что всегда можно довериться тому говну, которое генерит NHibernate,
Считаете Вы при чем не верно. А я знаю.
ВВ>Обычно вообще-то переход, скажем, на 10g превращается в масштабный и сложный проект и вовсе не потому, что там "бизнес-логика" в базе.
Бизнес логика в базе это одна из основных сложностей перевода проекта с одной СУБД на другую. Вот когда сами попробуете — узнаете.
Здравствуйте, criosray, Вы писали:
ВВ>>А, ну вы видимо считаете, что всегда можно довериться тому говну, которое генерит NHibernate, C>Считаете Вы при чем не верно. А я знаю.
Значит, плохо знаете.
ВВ>>Обычно вообще-то переход, скажем, на 10g превращается в масштабный и сложный проект и вовсе не потому, что там "бизнес-логика" в базе. C>Бизнес логика в базе это одна из основных сложностей перевода проекта с одной СУБД на другую. Вот когда сами попробуете — узнаете.
Попробую что?
Давай-те как посмотрим ваши посты:
— используем возможности СУБД на 20%
— проблем с производительностью нет
— переходим с Сиквел сервера на Оракл, ибо так хочет клиент
Да, и еще:
— 70 млн сущностей
— генерим запросы с помощью NHibernate
Это вот это я должен попробовать?
И вы все это описываете как хоть какой-то мало-мальски полезный опыт? Вы представляете, сколько лицензия на Оракл стоит? Клиент деньги отмывает? Или клиент — это дядя Ваня, который новый диск на горбушке купил?
Советую вам не судить о сложностях перехода с одной СУБД на другую на основе таких проектов.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Явно в проекте с базой на 70 млн. сущностей запросы ОРМ не стоит позволять генерить
Ага, и писать все на ассемблере.
ВВ>А сам апликейшин при нормальном дизайне не должен зависеть от базы, вообще независимо от того, ОРМ у вас там или не ОРМ.
И достигнуть этого можно двумя способами.
1)Перенести всю BL на SQL, что практически смертельно в случае смены БД, так как придется перекраивать кучу кода.
2)Использовать правильные инструменты для работы с БД, которые позволяют BL абстрагировать от хранилища, тогда и смена БД пройдет гладко.
ВВ>И вы все это описываете как хоть какой-то мало-мальски полезный опыт? Вы представляете, сколько лицензия на Оракл стоит? Клиент деньги отмывает? Или клиент — это дядя Ваня, который новый диск на горбушке купил?
Здравствуйте, gandjustas, Вы писали:
ВВ>>Явно в проекте с базой на 70 млн. сущностей запросы ОРМ не стоит позволять генерить G>Ага, и писать все на ассемблере.
Добро пожаловать в реальный мир, здесь иногда приходится писать запросы ручками.
ВВ>>А сам апликейшин при нормальном дизайне не должен зависеть от базы, вообще независимо от того, ОРМ у вас там или не ОРМ. G>И достигнуть этого можно двумя способами. G>1)Перенести всю BL на SQL, что практически смертельно в случае смены БД, так как придется перекраивать кучу кода. G>2)Использовать правильные инструменты для работы с БД, которые позволяют BL абстрагировать от хранилища, тогда и смена БД пройдет гладко.
Для тех в танке повторяю — вынесение BL из БД вовсе не означает "легкости смены СУБД", если, конечно же, речь не идет о хоум-пейджах.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Здравствуйте, gandjustas, Вы писали:
ВВ>>>Явно в проекте с базой на 70 млн. сущностей запросы ОРМ не стоит позволять генерить G>>Ага, и писать все на ассемблере.
ВВ>Добро пожаловать в реальный мир, здесь иногда приходится писать запросы ручками.
Только когда надо использовать возможности, не поддерживаемые высокоуровневыми средствами.
ВВ>>>А сам апликейшин при нормальном дизайне не должен зависеть от базы, вообще независимо от того, ОРМ у вас там или не ОРМ. G>>И достигнуть этого можно двумя способами. G>>1)Перенести всю BL на SQL, что практически смертельно в случае смены БД, так как придется перекраивать кучу кода. G>>2)Использовать правильные инструменты для работы с БД, которые позволяют BL абстрагировать от хранилища, тогда и смена БД пройдет гладко.
ВВ>Для тех в танке повторяю — вынесение BL из БД вовсе не означает "легкости смены СУБД", если, конечно же, речь не идет о хоум-пейджах.
Еще раз: главное абстрагировать BL от хранилища.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Обычно вообще-то переход, скажем, на 10g превращается в масштабный и сложный проект и вовсе не потому, что там "бизнес-логика" в базе.
Здравствуйте, _d_m_, Вы писали:
___>СУБД — да это определяется сразу. А вот перекидывать с одной СУБД на другую — тот еще гемор — заказчик посылается в лес.
Интересный подход однако, посылать заказчика. Жалко в ЖКХ где работает мой отец, об этом не знали. А то MSSQL выдохся и перешли на Оракл.
Здравствуйте, Воронков Василий, Вы писали:
G>>И достигнуть этого можно двумя способами. G>>1)Перенести всю BL на SQL, что практически смертельно в случае смены БД, так как придется перекраивать кучу кода. G>>2)Использовать правильные инструменты для работы с БД, которые позволяют BL абстрагировать от хранилища, тогда и смена БД пройдет гладко.
ВВ>Для тех в танке повторяю — вынесение BL из БД вовсе не означает "легкости смены СУБД", если, конечно же, речь не идет о хоум-пейджах.
ВВ>>Для тех в танке повторяю — вынесение BL из БД вовсе не означает "легкости смены СУБД", если, конечно же, речь не идет о хоум-пейджах.
I>Не спорь с ним, он сикп освоил
При чем, что очень похоже, по уровню достаточном только для "хоум пейдж"...
HL>>>>И уж поверьте, сервер не лезет в таблицы с метаданными для одинаковых запросов, там всё довольно хорошо кэшируется. C>>>За каждый промах кеша Вам придется платить. Вот и все.
HL>>Какой промах? План для "select *" ляжет в кэш планов и будет использован для всех аналогичных запросов. После этого Metadata lookup-а не будет. C>До того, как он ляжет в кеш планов и случится промах. Кроме того, кеш планов имеет такое ствойство как expiration date.
Промах случится для любого запроса, которого нет в кэше, будь это "select *" или "select список полей"
HL>>Даже для запросов, для которых плана нет, разница в "select *" и "select список полей" практически отсутствует, потому что и там и там будет просмотр метаданных и кучи еще чего. C>Продолжайте в это верить. А лучше почитайте статьи и не пишите больше глупостей.
Дальше читать не стал, бредом не увлекаюсь. Надеюсь вам не нужно доказывать, что это бред и в очередной раз приводить стоимость запросов с "select *", которые не приводят к table scan-у?
Здравствуйте, criosray, Вы писали:
___>>>>И это вобще-то ни мега-запрос, как тут уже сказали, запрос прост... Для тех кто в теме.
E__>>>Он может и прост, но выглядит довольно монструозно. А это само по себе плохо. Насколько я понимаю, linq создавался в том числе и для того, чтобы запросы выглядели не столь монстряче.
HL>>Может это от того, что вы просто не знаете t-sql? C>Нет, это от того, что вы не знаете ничего кроме t-sql (да и t-sql знаете ли Вы t-sql?).
Я вообще-то программирую на C# уже 8 лет, более того, сейчас занимаюсь этим в буржуинии (где всё-таки уровень повыше, чем в России).
HL>>А то можно и про какой-нибудь (условно) итальйнский (испанский, венгерский) язык сказать, что выглядит монстуозно, какие-то буковки непонятные и слова неизвестные.
HL>>Те кто в теме запрос понимают за 30 секунд. C>А что так долго-то? 30 мс не больше. Подумаешь, запрос на 5 страниц со множеством вложенных подзапросов, на который явно угробили десятки человеко-часов.
Здравствуйте, _d_m_, Вы писали:
___>Только плюс линку. Но заниматься преждевременной оптимизацией — "красивый рукопашный скрипт" — зло. Запросы надо писать так, как-будто ничего не знаешь про работу движка СУБД.
Ага. И с линком это получается намного лучше.
___>Классно. Но это хак. Оптимизатор СУБД должен этим заниматься.
Не, ну ты можешь конечно ждать, когда оптимизатор станет идеальным. Лично я предпочитаю смотреть на то, что есть в наличии.
___>PS: Речь изначально шла не об этом. Сначала gandjustas ляпнул ерунду (или коряво выразился), которую всем понять было только как: кэширование и индексы работают только для линк-запросов.
Ну, касательно ляпанья gandjustas все вопросы к нему, он много тут такой пурги несет, что одной больше, одной меньше ...
Здравствуйте, yuriylsh, Вы писали:
Y>Я отвечал на вполне конкретное заявление и iHateLogins вполне однозначно сказал то что сказал. Там не было ничего ни про массовые колличества ни про всегда плохо.
А давай мы не будем пытаться превратно трактовать, а прямо у него спросим — считает ли iHateLogins, что юнит-тесты это всегда плохо?
Здравствуйте, Ikemefula, Вы писали:
ВВ>>Обычно вообще-то переход, скажем, на 10g превращается в масштабный и сложный проект и вовсе не потому, что там "бизнес-логика" в базе. I>Поясни.
Переход с одной версии БД на другую в случае оракла — это очень нетривиальное занятие, т.к. изменения могут быть критичными для функционирования
приложения, ряд запросов возможно придётся переписать, какой-то функционал больше не поддерживается, зато появился новый итд итд итд.
Именно поэтому у многих сейчас работает оракл даже 8-й версии, хотя на дворе уже 11-я. Стоимость перехода неоправданно высока, такова жизнь.
Здравствуйте, Ночной Смотрящий, Вы писали:
Y>>Я отвечал на вполне конкретное заявление и iHateLogins вполне однозначно сказал то что сказал. Там не было ничего ни про массовые колличества ни про всегда плохо.
НС>А давай мы не будем пытаться превратно трактовать, а прямо у него спросим — считает ли iHateLogins, что юнит-тесты это всегда плохо?
Нет, я так не считаю. В некоторых проектах, связанных с мат. вычислениями, я использовал юнит-тесты по полной и это мне помогло сэкономить кучу времени при тестировании.
Здравствуйте, iHateLogins, Вы писали:
ВВ>>>Обычно вообще-то переход, скажем, на 10g превращается в масштабный и сложный проект и вовсе не потому, что там "бизнес-логика" в базе. I>>Поясни.
HL>Переход с одной версии БД на другую в случае оракла — это очень нетривиальное занятие, т.к. изменения могут быть критичными для функционирования HL>приложения, ряд запросов возможно придётся переписать, какой-то функционал больше не поддерживается, зато появился новый итд итд итд.
Меня интересует "вовсе не потому, что там "бизнес-логика" в базе", а ты пояснил как раз про бизнеслогику в базе
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, yuriylsh, Вы писали:
Y>>Я отвечал на вполне конкретное заявление и iHateLogins вполне однозначно сказал то что сказал. Там не было ничего ни про массовые колличества ни про всегда плохо.
НС>А давай мы не будем пытаться превратно трактовать,
Точно, давай не будем.
НС>а прямо у него спросим — считает ли iHateLogins, что юнит-тесты это всегда плохо?
Спрашивай, если хочеться. Мне абсолютно не интересно, что он по этому поводу считает. К словам, на которые я отвечал этот вопрос не имеет никакого отношения.
... << RSDN@Home 1.2.0 alpha 4 rev. 1228>>
Luck in life always exists in the form of an abstract class that cannot be instantiated directly and needs to be inherited by hard work and dedication.
Здравствуйте, Ikemefula, Вы писали:
ВВ>>>>Обычно вообще-то переход, скажем, на 10g превращается в масштабный и сложный проект и вовсе не потому, что там "бизнес-логика" в базе. I>>>Поясни.
HL>>Переход с одной версии БД на другую в случае оракла — это очень нетривиальное занятие, т.к. изменения могут быть критичными для функционирования HL>>приложения, ряд запросов возможно придётся переписать, какой-то функционал больше не поддерживается, зато появился новый итд итд итд.
I>Меня интересует "вовсе не потому, что там "бизнес-логика" в базе", а ты пояснил как раз про бизнеслогику в базе
Даже если логики (транзакций) в базе нет, наверняка там есть вьюхи, индексы, оптимизированные для спец. запросов, вычисляемые колонки с индексами на них для лучшей производительности, ETL для аналитики, итд итд. Всё это перенести с одной БД на другую — это совсем не тривиальное занятие.
___>>СУБД — да это определяется сразу. А вот перекидывать с одной СУБД на другую — тот еще гемор — заказчик посылается в лес. I>Интересный подход однако, посылать заказчика. Жалко в ЖКХ где работает мой отец, об этом не знали. А то MSSQL выдохся и перешли на Оракл.
Ну так если не знать как оптимизировать SQL Server, то переход на оракл не поможет. Это раз.
А во-вторых, лучше бы ЖКХ лучше занималось своими непосредственными задачами и уважало своих клиентов (владельцев квартир), а не занималось откатной хернёй с переходом на оракл (который стоит где-то в 20 раз дороже SQL Server).
Здравствуйте, iHateLogins, Вы писали: HL>Такой подход как у _d_m_ будет как раз самым быстрым.
Это, интересно, почему? Ты полагаешь, что SQL Server сам не умеет выкидывать промежуточные результаты на диск?
Единственное, где это может 100% помочь — когда один и тот же подзапрос используется дважды в рамках одной транзакции. Кросс-запросную оптимизацию сиквел, естественно, не делает.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, _d_m_, Вы писали:
___>>СУБД — да это определяется сразу. А вот перекидывать с одной СУБД на другую — тот еще гемор — заказчик посылается в лес.
I>Интересный подход однако, посылать заказчика.
Мы не собираемся прыгать аки горные козлики с одной СУБД на другую. Тем более нет прецендентов с производительностью, багами, или необходимостью каких-то супервозможностей и фич в другой СУБД. Поэтому резонный вопрос: а на каком основании переход на другую СУБД? Но клиентам глубоко побоку на СУБД, их интересует возможности продукта, а как оно там реализовано. Если клиент выдвигает неадекватные требования — есть другие клиенты.
I>Жалко в ЖКХ где работает мой отец, об этом не знали. А то MSSQL выдохся и перешли на Оракл.
Я не знаю как там в вашей местности с ЖКХ, но у нас ЖКХ это просто кровососы.
Здравствуйте, criosray, Вы писали:
HL>>Такой подход как у _d_m_ будет как раз самым быстрым.
C>Да уж... если уже писать глупости, так по полной не зная меры?
Прекрати некропостинг, если есть что по существу — пиши. Иначе "лучше жевать чем говорить".
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, iHateLogins, Вы писали: HL>>Такой подход как у _d_m_ будет как раз самым быстрым. S>Это, интересно, почему? Ты полагаешь, что SQL Server сам не умеет выкидывать промежуточные результаты на диск?
Может. Но все таки, еще раз: практическими экспирементами выявлено, это самый производительный вариант для любой комбинации входных параметров.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Здравствуйте, _d_m_, Вы писали:
___>>Только плюс линку. Но заниматься преждевременной оптимизацией — "красивый рукопашный скрипт" — зло. Запросы надо писать так, как-будто ничего не знаешь про работу движка СУБД.
НС>Ага. И с линком это получается намного лучше.
___>>Классно. Но это хак. Оптимизатор СУБД должен этим заниматься.
НС>Не, ну ты можешь конечно ждать, когда оптимизатор станет идеальным. Лично я предпочитаю смотреть на то, что есть в наличии.
Отвечу всем: ну не будем переписывать проект с нуля, т.к. линк такой вот прекрасный. Хватает и того, что есть без линка. Тем более: то он разрабатывается, то его там вроде хотели закрыть, а то опять он ожил. А MS SQL и его оптимизатор будут, и оптимизатор будут подтягивать.
___>>PS: Речь изначально шла не об этом. Сначала gandjustas ляпнул ерунду (или коряво выразился), которую всем понять было только как: кэширование и индексы работают только для линк-запросов.
НС>Ну, касательно ляпанья gandjustas все вопросы к нему, он много тут такой пурги несет, что одной больше, одной меньше ...
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, _d_m_, Вы писали:
___>>Ну это для детей. Для оптимизатора isnull — черный ящик. S>Ок. Теперь для взрослых: S>
S>select count(*) from sysobjects where id = @id or @id is null
S>
Если ты про = @Товар or @Товар is null, то он ваще не играет никакой роли. Писать отдельный запрос ради этого редкого частного случая смысла нет. Скорость приемлимая, и ради того чтобы юзер ждал 1 секунду вместо 5... оно того не стоит.
Здравствуйте, _d_m_, Вы писали: ___>Если ты про = @Товар or @Товар is null, то он ваще не играет никакой роли. Писать отдельный запрос ради этого редкого частного случая смысла нет. Скорость приемлимая, и ради того чтобы юзер ждал 1 секунду вместо 5... оно того не стоит.
Ну ок. Вас всё устраивает — не мне вас учить программировать.
Но не удивляйтесь, когда кто-то другой будет добиваться "приемлимой" скорости не многократными экспериментами и тяжкими усилиями, а просто наколбасит запрос на линке, и всё взлетит с первого раза.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, Ikemefula, Вы писали:
I>Здравствуйте, Воронков Василий, Вы писали:
G>>>И достигнуть этого можно двумя способами. G>>>1)Перенести всю BL на SQL, что практически смертельно в случае смены БД, так как придется перекраивать кучу кода. G>>>2)Использовать правильные инструменты для работы с БД, которые позволяют BL абстрагировать от хранилища, тогда и смена БД пройдет гладко.
ВВ>>Для тех в танке повторяю — вынесение BL из БД вовсе не означает "легкости смены СУБД", если, конечно же, речь не идет о хоум-пейджах.
I>Не спорь с ним, он сикп освоил
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, gandjustas, Вы писали:
G>>Еще раз: главное абстрагировать BL от хранилища.
HL>Как вам другая задача: абстрагировать BL от языка программирования. Возьмётесь?
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, _d_m_, Вы писали: ___>>Если ты про = @Товар or @Товар is null, то он ваще не играет никакой роли. Писать отдельный запрос ради этого редкого частного случая смысла нет. Скорость приемлимая, и ради того чтобы юзер ждал 1 секунду вместо 5... оно того не стоит. S>Ну ок. Вас всё устраивает — не мне вас учить программировать. S>Но не удивляйтесь, когда кто-то другой будет добиваться "приемлимой" скорости не многократными экспериментами и тяжкими усилиями, а просто наколбасит запрос на линке, и всё взлетит с первого раза.
Да не вопрос. Начинать новый проект — linq в руки и вперед. Но переписывать проект начатый в 2001 году мы не станем.
Здравствуйте, _d_m_, Вы писали: ___>Да не вопрос. Начинать новый проект — linq в руки и вперед. Но переписывать проект начатый в 2001 году мы не станем.
Еще раз: никто вас не уговаривает переписывать работающий восход с закатом. Напомню, что вы пытаетесь убедить нас, что и в новых проектах вот эти ваши дорогостоящие приседания на неприспособленном для программирования языке и есть руль. А линк — так, погулять вышел. Вот это и есть основное заблуждение.
Заранее хочу оговориться, а то в таких религиозных спорах часто приходится занимать несколько утрированную позицию: я не считаю конкретную реализацию Link2Sql панацеей. Она страдает множеством недостатков; и особо смелые парни из числа опытных собаководов сейчас полощут мозг команде авторов Linq на тему "вы всё сделали не так, иначе бы провайдер линка было бы легко написать". Но сам подход линка к решению задачи значительно лучше, чем подход T-SQL.
Понимаете, было время, когда опытные ассемблерщики смеялись над, скажем, С++. "Что он вам там наоптимизирует? Я вот заколбашу здесь rep scansd — и всё полетит, а где оно в C++?".
Но годы шли; смех сильно поутих после того, как оказалось, что и rep scansd, и прочее вполне себе подвластно компилятору. Более того, смеяться стали программисты на C++ — потому что они натравили новые компиляторы на старые программы и получили 150% прироста производительности. А ассемблерный код как был оптимальным для 80386, так для него оптимальным и остался. Отдельные кадры из числа особо упёртых продолжали смеяться над "корявым кодом", который генерировали компиляторы, даже в 2005 году. Лица этих отдельных кадров сильно вытягивались после просмотра результатов забега "корявого" кода под профайлером — rep scansd сливал. Оказалось, что Intel C/C++ Compiler знает об особенностях потрошков современных CPU немножко больше, чем среднестатистический ассемблерщик.
Такая же штука ожидает нас и в SQL. Понимаете, SQL — это ассемблер. Есть оптимизации, которые SQL Server не проводит и никогда не будет проводить. В простых случаях он справляется очень хорошо; но и ассемблер в простых случаях инкрементирует каунтер не шибко плохо. Но в сложных случаях руки оптимизатора связаны тем уровнем семантики, который ему видим. И в этом смысле линк позволяет развязать смысловую составляющую запроса и те кирпичики, из которых он сделан.
Классический пример — Skip(m).Take(n). Запрос, который вы нарулите вручную для MS SQL 2000, уже не будет самым эффективным на MS SQL 2005. И MS SQL 2005 не станет за вас переписывать его на оконные функции. А вот линк — станет. Потому, что линк видит суть запроса, а не нагромождение select top from select top.
И таких примеров в реальной жизни — очень и очень много. Вот вы помянули RLS. Очень часто в RLS есть режим "администратора", который типа видит всё. В классике вы будете делать джойн с таблицей ACL, оборудованный чем-то типа OR @userLevel == Admin. И сиквел будет честно сканировать ACL, просаживая производительность на порядок. А на linq приджойнивание ACL таблицы будет происходить в динамике, в зависимости от уровня доступа. И ненужные подзапросы даже не будут генерироваться.
В итоге, чем сложнее логика запроса — тем сильнее в нём будет рулить Linq. Вы совершенно напрасно пытаетесь показать те примеры, для которых линк и изобретался. Убийцы линка — это "простые" запросы, которые не пролезают через провайдера. Типа CTE. Вот в них можно положить линк на лопатки путём ручного кодирования.
... << RSDN@Home 1.2.0 alpha rev. 677>>
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
L>Отлично.
L>1. Если конструктор Customer() кинет исключение, тест не пройдет. L>2. Если Create() кинет исключение, тест не пройдет L>3. Если GetCustomerById() вернет что-то отличное от ожидаемого, тест провалится. L>4. Если впоследствии кто-то умный решит играться регистром имен в конструкторах, сеттерах или еще где, тест свалится
L>Нормальный тест.
Любой интеграционный тест использующий Customer и GetCustomerById проверит то же самое. Зачем отдельный юнит-тест?
L>>Отлично.
L>>1. Если конструктор Customer() кинет исключение, тест не пройдет. L>>2. Если Create() кинет исключение, тест не пройдет L>>3. Если GetCustomerById() вернет что-то отличное от ожидаемого, тест провалится. L>>4. Если впоследствии кто-то умный решит играться регистром имен в конструкторах, сеттерах или еще где, тест свалится
L>>Нормальный тест.
КБ>Любой интеграционный тест использующий Customer и GetCustomerById проверит то же самое.
Не любой, а каждый. И не просто проверит, а обязан проверять.
КБ>Зачем отдельный юнит-тест?
Затем чтобы не писать кучу ненужного кода.
Здравствуйте, Пацак, Вы писали:
П>Здравствуйте, Константин Б., Вы писали:
КБ>>Для меня фраза "интерфейс определяется тестами" — бессмыслица. Если функциональные тесты еще хоть как-то можно вывести из функциональных требований, то юнит-тесты проектируются "из головы", а то и подгоняются под уже придуманный интерфейс.
П>Вот именно так и получается: тесты выдумываются "из головы" — и в это время в голову приходит понимание того, каким должен быть интерфейс. П>Просто тест — это уже в каком-то смысле использование модуля, а практика показывает, что как бы хорошо модуль не был спроектирован и написан — с момента начала его эксплуатации о нем неминуемо узнаешь много нового и рука сама тянется к кнопке "переделать нафиг". Тесты позволяют нажать на эту кнопку чуть раньше — только и всего...
Если рука тянется к кнопке "переделать нафиг" значит модуль все таки был спроектирован плохо. Что если в реальности модуль будет использоваться не так как в тестах?
КБ>>Нет. Но презентация запрещает писать один тест на несколько классов.
П>Презентацию не смотрел ввиду угребищности ее формата, поэтому на всякий случай уточню: прям вот так вот и запрещает? Или просто говорит о том, что это неудобно?
Она говорит — что это уже не юнит-тест, а интеграционный тест, а значит это уже не так круто как юнит-тест, а что бы это был все-таки юнит-тест надо делать моки.
П>Просто на самом деле в большинстве случаев оно именно так и есть — проще написать два похожих теста для двух разных сущностей, чем потом пялиться на красную полоску и гадать — "а из-за кого она на этот раз?"
По вашему лучше пялиться на красную полоску и гадать "а что за тест на это раз упал?"?. Или все-таки лучше взглянуть на лог тестирования?
А ошибку вы будете исправлять силой мысли? Или все таки на сорцы взгляните?
Нет никакой разницы один там тест или десять если покрытие у них одинаковое.
Здравствуйте, Константин Б., Вы писали:
Б>Если рука тянется к кнопке "переделать нафиг" значит модуль все таки был спроектирован плохо.
Естественно, но с тестами ты гораздо раньше об этом узнаешь.
Б>Что если в реальности модуль будет использоваться не так как в тестах?
такое бывает при восходящем проектировании. если использовать нисходщее проектирование, то напимсанные пекред кодом тесты — и есть реальные сценарии использования.
КБ>Нет никакой разницы один там тест или десять если покрытие у них одинаковое.
Какое покрытие? Code Coverage, замеренное инструментально? Оно вообще-то слабо коррелирует с покрытием сценариев.
Чтобы добиться одинаковое покрытие сценариев кучки связаанных модулей понадобится гораздо больше интеграционных тестов написать.
Здравствуйте, gandjustas, Вы писали:
КБ>>Ну и ладно. Можно же просто рассказать о моках, о их пользе. А само применение моков оставить на усмотрение разработчика. G>Но это все же презентация, в ней надо побольше громких, желательно безапелляционных, заявлений делать. G>Ведь если честно все рассказать в презентации или в книге, то большинство скажет что это и так известно (что на самом деле является очень хорошей характеристикой). Хотя потом еще лет 10 цитировать будут.
Похоже кое-то тут в КСВ руководствуется этим же принципом. Сделать по больше громких, безапелляционных заявлений. На заявления "эти принципы применимы не всегда" — отвечать "нет, всегда". А на конкретные контрпримеры — "ну дык не надо слепо следовать принципам".
КБ>>>>Может тогда ну их нафиг эти правила, а? G>>>Нет, нафиг такой подход, когда читаешь кучу таких "правил", а потом слемо им следуешь. G>>>Это называется культ карго КБ>>А нафига правила если им нельзя следовать? G>Можно. Почитай по ссылке.
Так вы уж определитесь можно им следовать или нет. "Можно, но не совсем" = "Нельзя"
G>>>На практике человек не может обычно написать тесты для всех сценариев A и B, может получиться так что A использует B таким образом, что B в таком сценарии не тестировался. КБ>>Ага. Поэтому интеграционные тесты — рулят G>Совсем не рулят. Потому что если не человек не смог для изолированных компонент написать достаточно полный test-suite, то в случае тестирования группы компонент он вряд ли покроет тестами даже 10% сценариев.
А кто сказал, что "не смог"? Может просто решил не тратить зря время. И обоснуйте пожалуйста вашу оценку в 10%.
G>Вообще интеграционные тесты дают рост экспоненциальный количества тестов при увеличении связности и количества компонент.
Как показывает практика — не дают.
G>Тогда как количество unit-тестов растет линейно. Это уже не говоря о том что unit-тесты гораздо проще в написании, чем интеграционные.
Ну да. Моки там фигачить. Лишние интерфейсы вводить. Офигеть просто как проще.
КБ>>>>Ага. Но вместо того чтобы это объяснить, придумываются глупые правила. G>>>Сложно объяснять как правильно писать тесты, это также сложно как правильно писать код.
КБ>>Тесты надо писать так: КБ>>1. Чтобы они запускались автоматически КБ>>2. Чтобы тестировали то что нужно.
G>Всего-то G>А как определить что нужно тестировать?
Юнит-тесты ответа на это вопрос не дают.
G>А как писать тесты так, чтобы они не стали обузой?
Юнит-тесты ответа на это вопрос не дают.
G>А когда вообще писать тесты?
А вот это пофиг.
G>... G>продолжать можно долго. G>Для полноценной методаки тестирования нужно гораздо больше формализма и при этом должно быть понимание зачем это все делается.
Только вот ваш формализм плюет на эти вопросы.
КБ>>А будут ли они юнит или интеграционными, с моками или без — какая разница? Этому вопросу помоему уделяется неоправдано много внимания.
G>Я думаю что этому вопросу уделяется слишком мало внимания, так как ответы на такие вопросы делают тестирование эффективным.
Каким образом?
G>>>Я уже писал что самый лучший способ изучать TDD — смотреть видеозаписи о том как люди пишут код по TDD. КБ>>А нужно ли вообще изучать TDD? Это пока вопрос открытый G>Изучать по-любоу нужно
Зачем? Что такое TDD — вы не знаете. Как отличить TDD от не TDD — вы не знаете. Область применимости TDD — вы не знаете. Альтернатив вы кстати то же не знаете. Преимущества — сомнительны. Зачем вот ЭТО изучать?
Здравствуйте, gandjustas, Вы писали:
КБ>>Любой интеграционный тест использующий Customer и GetCustomerById проверит то же самое. G>Не любой, а каждый. И не просто проверит, а обязан проверять.
Можете написать любой хоть сколько нибудь осмысленный тест использующий Customer и GetCustomerById, который этого не проверит? Я вот не могу. Так зачем это еще и отдельно проверять?
КБ>>Зачем отдельный юнит-тест? G>Затем чтобы не писать кучу ненужного кода.
Здравствуйте, gandjustas, Вы писали:
G>Здравствуйте, Константин Б., Вы писали:
Б>>Если рука тянется к кнопке "переделать нафиг" значит модуль все таки был спроектирован плохо. G>Естественно, но с тестами ты гораздо раньше об этом узнаешь.
А может стоит все-таки проектировать хорошо?
Б>>Что если в реальности модуль будет использоваться не так как в тестах? G>такое бывает при восходящем проектировании. если использовать нисходщее проектирование, то напимсанные пекред кодом тесты — и есть реальные сценарии использования.
Тогда нафига юнит-тесты?
КБ>>Нет никакой разницы один там тест или десять если покрытие у них одинаковое. G>Какое покрытие? Code Coverage, замеренное инструментально? Оно вообще-то слабо коррелирует с покрытием сценариев.
А тебе с каким смыслом сложнее поспорить, вот тот и выбирай.
G>Чтобы добиться одинаковое покрытие сценариев кучки связаанных модулей понадобится гораздо больше интеграционных тестов написать.
Здравствуйте, iHateLogins, Вы писали:
___>>>СУБД — да это определяется сразу. А вот перекидывать с одной СУБД на другую — тот еще гемор — заказчик посылается в лес. I>>Интересный подход однако, посылать заказчика. Жалко в ЖКХ где работает мой отец, об этом не знали. А то MSSQL выдохся и перешли на Оракл.
HL>Ну так если не знать как оптимизировать SQL Server, то переход на оракл не поможет. Это раз.
А с чего ты взял что они чего то не знали с MSSQL ? Они не знали как послать заказчика.
HL>А во-вторых, лучше бы ЖКХ лучше занималось своими непосредственными задачами и уважало своих клиентов (владельцев квартир), а не занималось откатной хернёй с переходом на оракл (который стоит где-то в 20 раз дороже SQL Server).
Я вижу у тебя очень ловко получается решать задачи ничего не зная об условии оной. Продолжай !
Здравствуйте, Константин Б., Вы писали:
КБ>Здравствуйте, gandjustas, Вы писали:
КБ>>>Ну и ладно. Можно же просто рассказать о моках, о их пользе. А само применение моков оставить на усмотрение разработчика. G>>Но это все же презентация, в ней надо побольше громких, желательно безапелляционных, заявлений делать. G>>Ведь если честно все рассказать в презентации или в книге, то большинство скажет что это и так известно (что на самом деле является очень хорошей характеристикой). Хотя потом еще лет 10 цитировать будут.
КБ> Похоже кое-то тут в КСВ руководствуется этим же принципом. Сделать по больше громких, безапелляционных заявлений. На заявления "эти принципы применимы не всегда" — отвечать "нет, всегда". А на конкретные контрпримеры — "ну дык не надо слепо следовать принципам".
КБ>Так вы уж определитесь можно им следовать или нет. "Можно, но не совсем" = "Нельзя"
Ты путаешь принципы и сформулированные кем-то правила.
КБ>А кто сказал, что "не смог"? Может просто решил не тратить зря время. И обоснуйте пожалуйста вашу оценку в 10%.
Я уде приводил расчеты. С ростом связности системы количестве интеграционных тестов растет экспоненциально, а количество юнит-тестов почти линейно.
Соотвественно начиная с некоторого уровня сложности написание и поддержка интеграционных тестов станет непозволительно дорогоим занятием.
Поэтому по правилу 20\80 будет написано 20% тестов, которые реально покрывают только 10% наиболее вероятных сценариев.
G>>Вообще интеграционные тесты дают рост экспоненциальный количества тестов при увеличении связности и количества компонент. КБ>Как показывает практика — не дают.
Ну если практика заключается в неписании тестов, то да.
G>>Тогда как количество unit-тестов растет линейно. Это уже не говоря о том что unit-тесты гораздо проще в написании, чем интеграционные. КБ>Ну да. Моки там фигачить. Лишние интерфейсы вводить. Офигеть просто как проще.
А с чего ты взял что интерфейсы лишние? И в чем сложность моков? С моками тесты становятся гораздо понятнее, так как поведение связанного компонента описывается рядом с тестом.
КБ>>>Тесты надо писать так: КБ>>>1. Чтобы они запускались автоматически КБ>>>2. Чтобы тестировали то что нужно.
G>>Всего-то G>>А как определить что нужно тестировать?
КБ>Юнит-тесты ответа на это вопрос не дают.
Еще как дают — любой нетривиальный кусок кода, не завязанный на внешние компоненты.
G>>А как писать тесты так, чтобы они не стали обузой? КБ>Юнит-тесты ответа на это вопрос не дают.
Дают — писать тесты надо до кода, писать тесты для одного изолированного модуля.
G>>А когда вообще писать тесты? КБ>А вот это пофиг.
Совсем нет. Если изначально дизайн не рассчитан на тестирование, то потом написать тесты, особенно unit-тесты будет нереально сложно.
Обратное также верно, если тесты написаны до кода, то дизайн будет лего поддваваться тестированию. А это означает более низнкую связсность системы.
G>>... G>>продолжать можно долго. G>>Для полноценной методаки тестирования нужно гораздо больше формализма и при этом должно быть понимание зачем это все делается. КБ>Только вот ваш формализм плюет на эти вопросы.
См выше. Он дает настолько простые ответы, что ты до сих пор понять не можешь этого.
КБ>>>А будут ли они юнит или интеграционными, с моками или без — какая разница? Этому вопросу помоему уделяется неоправдано много внимания. G>>Я думаю что этому вопросу уделяется слишком мало внимания, так как ответы на такие вопросы делают тестирование эффективным.
КБ>Каким образом?
Таким что правльно написанные тесты очень сильно помогают в разработке и не требуют дофига времени на поддержку.
G>>>>Я уже писал что самый лучший способ изучать TDD — смотреть видеозаписи о том как люди пишут код по TDD. КБ>>>А нужно ли вообще изучать TDD? Это пока вопрос открытый G>>Изучать по-любоу нужно
КБ>Зачем? Что такое TDD — вы не знаете. Как отличить TDD от не TDD — вы не знаете. Область применимости TDD — вы не знаете. Альтернатив вы кстати то же не знаете. Преимущества — сомнительны. Зачем вот ЭТО изучать?
Все тут когда-то программирования не знали, и области его применения тоже, вот зачем его изучили?
Здравствуйте, Константин Б., Вы писали:
КБ>Здравствуйте, gandjustas, Вы писали:
КБ>>>Любой интеграционный тест использующий Customer и GetCustomerById проверит то же самое. G>>Не любой, а каждый. И не просто проверит, а обязан проверять.
КБ>Можете написать любой хоть сколько нибудь осмысленный тест использующий Customer и GetCustomerById, который этого не проверит? Я вот не могу. Так зачем это еще и отдельно проверять?
Ну для какого-то конкретного класса может ваши тесты все будут проверять, а в общем случае замучаетесь одно и тоже писать.
КБ>>>Зачем отдельный юнит-тест? G>>Затем чтобы не писать кучу ненужного кода.
КБ>Ненужный код — вот этот самый юнит-тест.
Юнит-тест — один и короткий, ты предлагаешь дублировать кучу кода вовсех интеграционных тестах.
Здравствуйте, Константин Б., Вы писали:
КБ>Здравствуйте, gandjustas, Вы писали:
G>>Здравствуйте, Константин Б., Вы писали:
Б>>>Если рука тянется к кнопке "переделать нафиг" значит модуль все таки был спроектирован плохо. G>>Естественно, но с тестами ты гораздо раньше об этом узнаешь.
КБ>А может стоит все-таки проектировать хорошо?
Ага, напиши методику, которая тебе гарантированно даст хороший дизайн в любом случае.
Б>>>Что если в реальности модуль будет использоваться не так как в тестах? G>>такое бывает при восходящем проектировании. если использовать нисходщее проектирование, то напимсанные пекред кодом тесты — и есть реальные сценарии использования. КБ>Тогда нафига юнит-тесты?
Так описанные выше тесты — и есть unit-тесты.
G>>Чтобы добиться одинаковое покрытие сценариев кучки связаанных модулей понадобится гораздо больше интеграционных тестов написать. КБ>Практика показывает обратное
Ну если практика заключается в неписании тестов, то да.
Здравствуйте, Ikemefula, Вы писали:
ВВ>>Обычно вообще-то переход, скажем, на 10g превращается в масштабный и сложный проект и вовсе не потому, что там "бизнес-логика" в базе. I>Поясни.
Ну потому что не переходят обычно "просто так" Многие приложения в огромных компаниях часто крутятся на древних СУБД. И представьте, что вы какую-нибудь систему "документооборота" хотите перевести с антикварного Оракла. А там все документы хранятся в ЛОНГЕ, который а) не поддерживает транзакции и б) имеет ограничения по размеру. И таких нюансов может быть множество.
Здравствуйте, _d_m_, Вы писали:
___>Отвечу всем: ну не будем переписывать проект с нуля, т.к. линк такой вот прекрасный.
Какой проект? Отвечай всем в другой ветке, я никакой такой конкретный проект не обсуждал.
___> Тем более: то он разрабатывается, то его там вроде хотели закрыть, а то опять он ожил. А MS SQL и его оптимизатор будут, и оптимизатор будут подтягивать.
Пока Вилла Риба ждет улучшения оптимизатора, Вилла Баджо зрабатывает бабки.
Здравствуйте, yuriylsh, Вы писали:
Y>Спрашивай, если хочеться. Мне абсолютно не интересно, что он по этому поводу считает.
5 баллов. Конечно, куда удобнее приписать собеседнику то, что он не говорил, и потом с блеском громить несуществующую позицию. Браво.
Y> К словам, на которые я отвечал этот вопрос не имеет никакого отношения.
Здравствуйте, Воронков Василий, Вы писали:
ВВ>Ну потому что не переходят обычно "просто так" Многие приложения в огромных компаниях часто крутятся на древних СУБД. И представьте, что вы какую-нибудь систему "документооборота" хотите перевести с антикварного Оракла. А там все документы хранятся в ЛОНГЕ, который а) не поддерживает транзакции и б) имеет ограничения по размеру. И таких нюансов может быть множество.
Мне это напоминает выкрики MS фанбоев в 2003 году, когда все хотели похоронить HTML и везде запихнуть XAML. Типа более новое, managed, векторное и пр.
И, простите, где ваш XAML? А вот HTML еще жив, курилка, новая версия выходит (HTML5), более того, веб-девелоперы сейчас куда как более внимательно относятся к HTML.
LINQ — изобретение чисто майкрософтовское, поэтому настоящего девелоперского комьюнити вокруг него не будет никогда. А SQL жил, жив, поддерживается в триллионе баз данных и срать хотел с колокольни на ваш линк.
Еще полгода назад MS хотел депрекейтнуть этот l2s, EF же в настоящий момент вообще не предназначен для какой-либо серьёзной работы.
Здравствуйте, iHateLogins, Вы писали:
HL>Здравствуйте, Eugeny__, Вы писали:
___>>>И это вобще-то ни мега-запрос, как тут уже сказали, запрос прост... Для тех кто в теме.
E__>>Он может и прост, но выглядит довольно монструозно. А это само по себе плохо. Насколько я понимаю, linq создавался в том числе и для того, чтобы запросы выглядели не столь монстряче.
HL>Может это от того, что вы просто не знаете t-sql?
Да, я действительно досконально, до мелочей его не знаю, хотя когда-то работал с ms-sql(хотя больше довелось с ms-sql ce, но это другая история) — мне с проблемами производительности сталкиваться не приходилось, хотя логику я максимально выносил в гораздо более читабельный C#(тем самым запросы были вроде "select a,b from c where d=e").
Приведенный код реально макаронный.
HL>Те кто в теме запрос понимают за 30 секунд.
Вот вот.
Понимаешь, современные языки и технологии стремятся к тому, что для того, чтобы прочесть код, не нужно быть гуру этого языка. Я могу понять, что там происходит, но меня воротит от одного вида такого кода.
Новости очень смешные. Зря вы не смотрите. Как будто за наркоманами подсматриваешь. Только тетка с погодой в завязке.
There is no such thing as a winnable war.
Здравствуйте, iHateLogins, Вы писали:
HL>LINQ — изобретение чисто майкрософтовское, поэтому настоящего девелоперского комьюнити вокруг него не будет никогда.
Угу. Как нет таких комьюнити вокруг .net, DX, MS SQL...
HL>А SQL жил, жив
Здравствуйте, iHateLogins, Вы писали:
HL>Мне это напоминает выкрики MS фанбоев в 2003 году, когда все хотели похоронить HTML и везде запихнуть XAML. Типа более новое, managed, векторное и пр.
HL>И, простите, где ваш XAML? А вот HTML еще жив, курилка, новая версия выходит (HTML5), более того, веб-девелоперы сейчас куда как более внимательно относятся к HTML.
Наш замл живет и здравствует. WPF и Silverlight базируются на замле. На WPF написаны кроме прочего интерфейсы AutoCAD и VS 2010.
Смотрите только — галстуком не поперхнитесь от такой-то новости...
Здравствуйте, criosray, Вы писали:
HL>>Мне это напоминает выкрики MS фанбоев в 2003 году, когда все хотели похоронить HTML и везде запихнуть XAML. Типа более новое, managed, векторное и пр.
HL>>И, простите, где ваш XAML? А вот HTML еще жив, курилка, новая версия выходит (HTML5), более того, веб-девелоперы сейчас куда как более внимательно относятся к HTML. C>Наш замл живет и здравствует. WPF и Silverlight базируются на замле. На WPF написаны кроме прочего интерфейсы AutoCAD и VS 2010.
Интересно, сколько сайтов используют WPF или СЛ? 0.01%? 0.1%?
Что касается автокада, то на впф там написан только тулбар, да еще мс отвалила кууучу баблосов аутодеску чтобы те засунули этот несчастный wpf в автокад.
Здравствуйте, iHateLogins, Вы писали:
HL>>>Мне это напоминает выкрики MS фанбоев в 2003 году, когда все хотели похоронить HTML и везде запихнуть XAML. Типа более новое, managed, векторное и пр.
HL>>>И, простите, где ваш XAML? А вот HTML еще жив, курилка, новая версия выходит (HTML5), более того, веб-девелоперы сейчас куда как более внимательно относятся к HTML. C>>Наш замл живет и здравствует. WPF и Silverlight базируются на замле. На WPF написаны кроме прочего интерфейсы AutoCAD и VS 2010.
HL>Интересно, сколько сайтов используют WPF или СЛ? 0.01%? 0.1%?
Этим технологиям полтора года от роду фактически. Конечно же потребуется время, чтоб они набрали обороты.
HL>Что касается автокада, то на впф там написан только тулбар,
Кто Вам эту чушь сказал?
HL>да еще мс отвалила кууучу баблосов аутодеску
Доказательства будут или очередной плод Вашего воспаленного воображения?
HL>чтобы те засунули этот несчастный wpf в автокад.
Вам не надоело еще писать глупости?
Здравствуйте, Константин Б., Вы писали:
КБ>Если рука тянется к кнопке "переделать нафиг" значит модуль все таки был спроектирован плохо.
Необязательно — он еще может быть хреново закодирован. В результате его интерфейс будет на 100% соответствовать спецификации, но внутри будет твориться тако-о-о-ое.....
КБ>Что если в реальности модуль будет использоваться не так как в тестах?
...а вот в этом случае — да, судя по всему он именно плохо спроектирован. Ибо работающим с ним людям непонятно, как правильно его использовать. Причем в случае, когда тесты пишутся параллельно с написанием модуля — непонятки с его использованием с немалой вероятностью вылезут уже на этом этапе, а не после сдачи модуля в эксплуатацию.
КБ>>>презентация... ...говорит — что это уже не юнит-тест, а интеграционный тест
Согласитесь, это все-таки не то же самое, что "запрещает писать один тест на несколько классов"?
КБ>а значит это уже не так круто как юнит-тест, а что бы это был все-таки юнит-тест надо делать моки.
"Круто" — это прям так в презентации и сказано? Или это вы снова от себя, а там даны более объективные показатели? У меня вот есть такое ИМХО, что юнит-тесты и интеграционные тесты по "крутости" находятся где-то на одном уровне. А вот по выполняемым задачам — они совершенно различны.
А моки — да, можно делать. И это гораздо удобнее, чем на каждый чих писать интеграционный тест.
КБ>По вашему лучше пялиться на красную полоску и гадать "а что за тест на это раз упал?"?. Или все-таки лучше взглянуть на лог тестирования?
Вопрос не в том, какой тест упал — это-то, да, видно в логе. Вопрос в том, на каком классе он упал. Стратегия "один класс <-> один и более тестов" позволяет однозначно определить первое по второму, сразу, с первого взгляда. Тогда как при обратном подходе (один тест на восемнадцать классов) этот процесс уже далеко не так прост и очевиден.
КБ>А ошибку вы будете исправлять силой мысли? Или все таки на сорцы взгляните?
Гляну, разумеется. На сорцы нужного класса.
КБ>Нет никакой разницы один там тест или десять если покрытие у них одинаковое.
Здравствуйте, Константин Б., Вы писали:
КБ>Любой интеграционный тест использующий Customer и GetCustomerById проверит то же самое. Зачем отдельный юнит-тест?
Вот как раз затем, чтобы не ждать, пока будет написан интеграционный.
Аналогия: зачем расчитывать прочность деталей кузова легковушки на компьютере, если можно создать живой автомобиль и устроить ему краш-тест? Казалось бы — если мы лажанулись в толщине какого-нибудь швелеера или трубки, то это будет сразу видно, когда мы "убьем машину об стену". Красота? Красота — можно уволить САПРовцев и сисадминов, компы продать и сэкономить на электричестве. Однако ж — продолжают почему-то считать...
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>>>А мой — уменьшается в два раза. Мое имхо против твоего имха? L>>Референсы будут? У меня — без проблем. НС>Пока что никаких референсов от тебя не видно, одни имхи.
Сначала Вы.
Здравствуйте, Пацак, Вы писали:
П>Здравствуйте, Константин Б., Вы писали: КБ>>Если рука тянется к кнопке "переделать нафиг" значит модуль все таки был спроектирован плохо. П>Необязательно — он еще может быть хреново закодирован. В результате его интерфейс будет на 100% соответствовать спецификации, но внутри будет твориться тако-о-о-ое.....
Напомню контекст:
Просто тест — это уже в каком-то смысле использование модуля, а практика показывает, что как бы хорошо модуль не был спроектирован и написан — с момента начала его эксплуатации о нем неминуемо узнаешь много нового и рука сама тянется к кнопке "переделать нафиг". Тесты позволяют нажать на эту кнопку чуть раньше — только и всего...
Если код на 100% соответсвует спецификации чем тут помогут тесты?
КБ>>Что если в реальности модуль будет использоваться не так как в тестах?
П>...а вот в этом случае — да, судя по всему он именно плохо спроектирован. Ибо работающим с ним людям непонятно, как правильно его использовать. Причем в случае, когда тесты пишутся параллельно с написанием модуля — непонятки с его использованием с немалой вероятностью вылезут уже на этом этапе, а не после сдачи модуля в эксплуатацию.
Еще раз напомню контекст:
Вот именно так и получается: тесты выдумываются "из головы" — и в это время в голову приходит понимание того, каким должен быть интерфейс.
Что если в реальности понадобится другой интерфейс, а не тот что вы придумали для тестов?
КБ>>>>презентация... ...говорит — что это уже не юнит-тест, а интеграционный тест П>Согласитесь, это все-таки не то же самое, что "запрещает писать один тест на несколько классов"?
Предисывать всегда использовать моки тождественно равно запрету писать один тест на несколько классов.
КБ>>а значит это уже не так круто как юнит-тест, а что бы это был все-таки юнит-тест надо делать моки.
П>"Круто" — это прям так в презентации и сказано? Или это вы снова от себя, а там даны более объективные показатели? У меня вот есть такое ИМХО, что юнит-тесты и интеграционные тесты по "крутости" находятся где-то на одном уровне. А вот по выполняемым задачам — они совершенно различны.
Нет там никаких объективных показателей показателей, ни обоснований. Просто "Пиши тесты! Пиши моки! Будешь спать как ребенок!".
П>А моки — да, можно делать. И это гораздо удобнее, чем на каждый чих писать интеграционный тест.
Удобнее ввести дополнительные интерфейсы и написать мок, чем всего лишь написать тест тестирующий два класса?
КБ>>По вашему лучше пялиться на красную полоску и гадать "а что за тест на это раз упал?"?. Или все-таки лучше взглянуть на лог тестирования? П>Вопрос не в том, какой тест упал — это-то, да, видно в логе. Вопрос в том, на каком классе он упал. Стратегия "один класс <-> один и более тестов" позволяет однозначно определить первое по второму, сразу, с первого взгляда. Тогда как при обратном подходе (один тест на восемнадцать классов) этот процесс уже далеко не так прост и очевиден.
Т.е. стектрейс это для вас сложно и не очевидно?
КБ>>А ошибку вы будете исправлять силой мысли? Или все таки на сорцы взгляните? П>Гляну, разумеется. На сорцы нужного класса.
Пока вы будете разглядывать сорцы класса, я просто перейду к месту падения ассерта или выброса исключения. Так что баг я поправлю раньше.
КБ>>Нет никакой разницы один там тест или десять если покрытие у них одинаковое.
П>В том-то и дело, что оно не одинаковое.
Практика не показывает превосхожство юнит-тестов в этом вопросе.
Здравствуйте, Пацак, Вы писали:
КБ>>Любой интеграционный тест использующий Customer и GetCustomerById проверит то же самое. Зачем отдельный юнит-тест? П>Вот как раз затем, чтобы не ждать, пока будет написан интеграционный.
А зачем его ждать? Взять и написать.
П>Аналогия: зачем расчитывать прочность деталей кузова легковушки на компьютере, если можно создать живой автомобиль и устроить ему краш-тест? Казалось бы — если мы лажанулись в толщине какого-нибудь швелеера или трубки, то это будет сразу видно, когда мы "убьем машину об стену". Красота? Красота — можно уволить САПРовцев и сисадминов, компы продать и сэкономить на электричестве. Однако ж — продолжают почему-то считать...
Аналогии показывают вашу неспособность выстроить причинно-следственную связь: "юнит-тесты" => "хороший результат". Видимо потому что ее все-таки нет.
Здравствуйте, gandjustas, Вы писали:
Б>>>>Если рука тянется к кнопке "переделать нафиг" значит модуль все таки был спроектирован плохо. G>>>Естественно, но с тестами ты гораздо раньше об этом узнаешь. КБ>>А может стоит все-таки проектировать хорошо? G>Ага, напиши методику, которая тебе гарантированно даст хороший дизайн в любом случае.
Б>>>>Что если в реальности модуль будет использоваться не так как в тестах? G>>>такое бывает при восходящем проектировании. если использовать нисходщее проектирование, то напимсанные пекред кодом тесты — и есть реальные сценарии использования. КБ>>Тогда нафига юнит-тесты? G>Так описанные выше тесты — и есть unit-тесты.
Ну какие же это юнит-тесты, когда они самые что ни наесть функциональные?
G>>>Чтобы добиться одинаковое покрытие сценариев кучки связаанных модулей понадобится гораздо больше интеграционных тестов написать. КБ>>Практика показывает обратное G>Ну если практика заключается в неписании тестов, то да.
Т.е. вы утверждаете что практика неписания тестов показывает что для одинакового покрытия интеграционных тестов, понадобится больше чем юнит-тестов? Каким образом?
Здравствуйте, Константин Б., Вы писали:
КБ>Здравствуйте, gandjustas, Вы писали:
Б>>>>>Если рука тянется к кнопке "переделать нафиг" значит модуль все таки был спроектирован плохо. G>>>>Естественно, но с тестами ты гораздо раньше об этом узнаешь. КБ>>>А может стоит все-таки проектировать хорошо? G>>Ага, напиши методику, которая тебе гарантированно даст хороший дизайн в любом случае.
КБ>Можешь начать с http://www.ozon.ru/context/detail/id/2796658/
Почему ОО-моделирование дает в среднем более хреновый результат, чем функциональное проектирование?
Б>>>>>Что если в реальности модуль будет использоваться не так как в тестах? G>>>>такое бывает при восходящем проектировании. если использовать нисходщее проектирование, то напимсанные пекред кодом тесты — и есть реальные сценарии использования. КБ>>>Тогда нафига юнит-тесты? G>>Так описанные выше тесты — и есть unit-тесты.
КБ>Ну какие же это юнит-тесты, когда они самые что ни наесть функциональные?
Если компонет не имеет внешних зависимостей, то unit-тест == интеграционный тест == приемочный тест.
А если есть внешние зависимости, то проще описать работу компонента абстрагируясь от зависимостей, этои будет unit-тест.
Например есть у тебя компонент БЛ, который считает ЗП сотрудникам по некоторым фходным данным. Гораздо проще протестировать описывать компонент так, чтобы абстрагироваться от того как данные получены. Сценарии работы, записанные таким образом и будут unit-тестами, а функциональные тесты в данном случае должны проверять работу компонента в готовой системе.
G>>>>Чтобы добиться одинаковое покрытие сценариев кучки связаанных модулей понадобится гораздо больше интеграционных тестов написать. КБ>>>Практика показывает обратное G>>Ну если практика заключается в неписании тестов, то да.
КБ>Т.е. вы утверждаете что практика неписания тестов показывает что для одинакового покрытия интеграционных тестов, понадобится больше чем юнит-тестов? Каким образом?
Не больше, а не меменьше.
А если серьезно, попробуйте привести пример кода, или дайте ссылку на какой-либо пример, где показано что для одинакового покрытия функционала нужно интеграционных тестов меньше, чем unit-тестов. А то пока что ваши утверждения противоречат теоретическим рассуждениям и практике многих людей.
Здравствуйте, Константин Б., Вы писали:
П>>Вот как раз затем, чтобы не ждать, пока будет написан интеграционный. КБ>А зачем его ждать? Взять и написать.
Поверх одного-единственного написанного (или в случае TDD — даже еще не написанного) модуля? Любопытное у вас понимание интеграционных тестов.
КБ>Аналогии показывают вашу неспособность выстроить причинно-следственную связь: "юнит-тесты" => "хороший результат".
А она ровно такая же, как и в более общем случае: "тесты вообще" -> "хороший результат". Если вы не в силах ее понять — это уже не наши проблемы.
Здравствуйте, gandjustas, Вы писали:
Б>>>>>>Если рука тянется к кнопке "переделать нафиг" значит модуль все таки был спроектирован плохо. G>>>>>Естественно, но с тестами ты гораздо раньше об этом узнаешь. КБ>>>>А может стоит все-таки проектировать хорошо? G>>>Ага, напиши методику, которая тебе гарантированно даст хороший дизайн в любом случае.
КБ>>Можешь начать с http://www.ozon.ru/context/detail/id/2796658/
Здравствуйте, Константин Б., Вы писали:
П>>Необязательно — он еще может быть хреново закодирован. В результате его интерфейс будет на 100% соответствовать спецификации, но внутри будет твориться тако-о-о-ое..... КБ>Если код на 100% соответсвует спецификации чем тут помогут тесты?
Не код — интерфейс. Формат торчащих наружу данных и сигнатуры методов, описанные в проектной документации. Что само по себе еще никак не гарантирует, что модуль будет работать правильно — именно это-то и позволят проверить тесты.
КБ>Что если в реальности понадобится другой интерфейс, а не тот что вы придумали для тестов?
Если тесты пишутся ориентируясь на реальную потребность (а так оно обычно и есть), то не понадобится. Только в случае, если накосячили те, кто эту самую потребность проектировал.
КБ>>>>>презентация... ...говорит — что это уже не юнит-тест, а интеграционный тест П>>Согласитесь, это все-таки не то же самое, что "запрещает писать один тест на несколько классов"? КБ>Предисывать всегда использовать моки тождественно равно запрету писать один тест на несколько классов.
Презентация предписывает всегда использовать моки? В том числе в интеграционных тестах?! Или все-таки вы снова немного нафантазировали и на самом деле предписывается их использовать не "всегда", а "всегда, когда это удобно и оправдано"?
КБ>Удобнее ввести дополнительные интерфейсы и написать мок, чем всего лишь написать тест тестирующий два класса?
Как правило — да.
КБ>Т.е. стектрейс это для вас сложно и не очевидно?
Еще раз: для того, чтобы просмотреть стекстрейс — тест нужно запустить руками и просмотреть его глазами.
КБ>Пока вы будете разглядывать сорцы класса, я просто перейду к месту падения ассерта или выброса исключения.
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Слив засчитан
Вот и ладненько.
Всем остальным — готов предоставить в личку телефоны и электронные адреса соучаснегов, начальников и даже представителей клиентов моих успешных TDD проектов. Только при одном условии — сначала с Вас референсы на проекты, где отказ от тестирования дал какой-то выигрыш.
Здравствуйте, Константин Б., Вы писали:
КБ>Т.е. стектрейс это для вас сложно и не очевидно?
В некоторых случаях, которых может быть и 90%, он очевиден. Но в остальных — нет. Потому что стектрейс проблемы, которая возникла при испытании уже сводного комплекса из дофига отдельных микрокомпонент (модули, классы), может давать эффекты проблемы, наведённой предыдущей работой (которая, однако, не вывалилась, а подложила свинью потомкам). Я говорю не о теоретической возможности, а о практически наблюдаемых ситуациях — причём достаточно часто.
И вот в случае таких ситуаций, если ранее части не были покрыты юнит-тестами и функциональными тестами микрокомпонент, возникает неодолимое желание срочно сделать это.:)
КБ>Если код на 100% соответсвует спецификации чем тут помогут тесты?
Именно дополнительным аргументом, что он таки на 100% (ну ладно, на 99.99%) соответствует спецификации.
КБ>Еще раз напомню контекст: КБ>
КБ>Вот именно так и получается: тесты выдумываются "из головы" — и в это время в голову приходит понимание того, каким должен быть интерфейс.
КБ>Что если в реальности понадобится другой интерфейс, а не тот что вы придумали для тестов?
Если при этом нет глобальных изменений внутренностей — тесты уже дали своё положительное влияние контролем ошибок, а переделать на новый интерфейс можно всегда.
КБ>Предисывать всегда использовать моки тождественно равно запрету писать один тест на несколько классов.
Не вижу никаких оснований для подобного вывода.
КБ>>>А ошибку вы будете исправлять силой мысли? Или все таки на сорцы взгляните? П>>Гляну, разумеется. На сорцы нужного класса. КБ>Пока вы будете разглядывать сорцы класса, я просто перейду к месту падения ассерта или выброса исключения. Так что баг я поправлю раньше.
Не поправите, потому что место реальной ошибки находится в совсем другом модуле. Простой пример: исключение вылетает потому, что сгенерирован ответ для уже завершённой транзакции (на которую ответ уже дан и клиент другого не ожидает). Ответ был передан отправкой сообщения во входную очередь модуля уровня транзакций. Сформировавший этот ответ модуль принял входные данные (в том числе ID транзакции) из третьего модуля, который воспользовался данными четвёртого модуля, ведущего базу трансляции внутренних идентификаторов запросов во внешние, и который вытащил не тот элемент из базы; реальная же ошибка всё-таки в третьем модуле, но в другой функции, в которой перепутаны аргументы в вызове промежуточной же функции из третьего модуля, формирующей запрос для четвёртого (база трансляции). Вот теперь Вы со своим "перейду к месту выброса исключения" обкуритесь в стороне, но не найдёте источник проблемы. В то же время, тест третьего модуля мог отловить эту ситуацию на месте и в предельно ясном виде.
Ещё хуже, когда какой-то модуль нарушает целостность памяти — внешне видимая ошибка может произойти где угодно и как угодно. Поэтому, все юнит-тесты и локальные функциональные тесты желательно пускать под отладчиком памяти или с диагностическими распределителями.
КБ>>>Нет никакой разницы один там тест или десять если покрытие у них одинаковое. П>>В том-то и дело, что оно не одинаковое. :-\ КБ>Практика не показывает превосхожство юнит-тестов в этом вопросе. :))
Полное превосходство — нет. Существенную фактическую полезность, достаточную, чтобы применять почти во всех случаях — да, показывает.
Здравствуйте, Пацак, Вы писали:
П>Вот как раз затем, чтобы не ждать, пока будет написан интеграционный.
П>Аналогия: зачем расчитывать прочность деталей кузова легковушки на компьютере, если можно создать живой автомобиль и устроить ему краш-тест? Казалось бы — если мы лажанулись в толщине какого-нибудь швелеера или трубки, то это будет сразу видно, когда мы "убьем машину об стену". Красота? Красота — можно уволить САПРовцев и сисадминов, компы продать и сэкономить на электричестве. Однако ж — продолжают почему-то считать... ;)
Между прочим, общались тут с одним самолётным КБ. Обсчёты аэродинамики дают точность около пяти знаков по основным количественным показателям (скорости потоков, давления и т.д.), а натурные испытания — не больше трёх, и при этом сам факт работы датчика вносит локальное нарушение. Поэтому — считают и данные берут из расчётов, а натурные испытания оставляют для качественной проверки модули (что вообще правильно её применили и результаты сходятся).
Так что дело не только в экономии денег на машины:) Локальные тесты дадут результат проверки локального соответствия ожидаемому — точнее, успешнее и быстрее.
Здравствуйте, criosray, Вы писали:
C>Здравствуйте, gandjustas, Вы писали:
Б>>>>>>>Если рука тянется к кнопке "переделать нафиг" значит модуль все таки был спроектирован плохо. G>>>>>>Естественно, но с тестами ты гораздо раньше об этом узнаешь. КБ>>>>>А может стоит все-таки проектировать хорошо? G>>>>Ага, напиши методику, которая тебе гарантированно даст хороший дизайн в любом случае.
КБ>>>Можешь начать с http://www.ozon.ru/context/detail/id/2796658/