Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: [1]   Вниз
  Печать  
Автор Тема: Разработка на языке C, управляемая тестированием  (Прочитано 19851 раз)
0 Пользователей и 1 Гость смотрят эту тему.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« : 26-07-2011 11:13 » 

Обсуждение статьи: «Разработка на языке C, управляемая тестированием»
« Последнее редактирование: 27-07-2011 23:55 от Dale » Записан

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #1 : 27-07-2011 19:14 » 

Думаю, в статье еще не хватает ссылки на "Обработка исключений на языке C".
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #2 : 27-07-2011 23:56 » 

Точно, спасибо! Собирался, но что-то меня такой объем залпом утомил.
Записан

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 28-07-2011 07:07 » 

Цитата: Dale
РУТ — одна из основ так называемых «гибких» (agile) технологий разработки, популярность которых в настоящее время стремительно возрастает («гибкими» они называются из-за способности приспосабливаться к динамичным, постоянно меняющимся требованиям к изделию).
Agile - модное слово.

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

Однако сдвиг и совмещение фаз по времени вовсе не сокращает трудозатраты. Сокращаются лишь простои отдельных членов команды и тем самым повышается производительность труда и снижаются издержки процесса. Хотя это и очень важно, но это слабо влияет на гибкость.

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

Я согласен с Вадом (было у нас частное обсуждение вне форума), что комплекс тестов плохо заменяет спецификации. Так как форма спецификации гораздо удобнее для чтения, для review, для обсуждения с заказчиком, нежели форма тестов.

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

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

Наконец, важный вопрос сочетания тестов и архитектуры решения. Какие-то тесты не зависят от архитектуры (и с их помощью можно оценить адекватность архитектуры требованиям), какие-то тесты прямо зависят от архитектуры (хотя бы на уровне форматов данных и порядка событий). Однако архитектура нередко также разрабатывается при помощи итеративных уточнений и опробаций. Для этого нужно осуществлять прототипирование, а прототипы - заведомо временные (часто одноразовые) артефакты. Если этот исследовательский процесс нагружать разработкой тестов, весь процесс разработки станет заметно неповоротливее и трудозатратнее, и большая часть этих трудозатрат пойдёт в мусор - такой эффект прямо противоположен по смыслу гибкости разработки.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #4 : 28-07-2011 08:04 » new

По большому счёту, когда говорят РУТ, нередко предлагают заменить написание спецификаций на разработку тестов.

Это особенность не РУТ, а "экстремального" программирования. Вполне можно сочетать РУТ с более привычными спецификациями.

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

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

Однако сдвиг и совмещение фаз по времени вовсе не сокращает трудозатраты.

Есть другие данные относительно зависимости стоимости исправления ошибки от времени ее обнаружения - чем раньше, тем проще. При грамотном применении РУТ большинство ошибок обнаруживаются и устраняются немедленно (сам подход запрещает реализацию новой функциональности, пока не прошли все имеющиеся тесты).

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

Боюсь, дослушав эту фразу до конца, многие разработчики спросят: "А с кем это вы сейчас разговаривали?". Предложите практически приемлемую методику оценки устойчивости информационных структур к изменениям, тогда рекомендация действительно приобретет ценность.

Я согласен с Вадом (было у нас частное обсуждение вне форума), что комплекс тестов плохо заменяет спецификации.

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

Тесты - это тоже программы, но почему-то при обсуждении РУТ качество тестов остаётся за скобками.

Неверно. Неоднократно акцентируется внимание на том, что тест обязан быть элементарным (четыре простейших фазы) и по возможности иметь линейную логику (к сожалению, в Unity это не всегда возможно, если задействованы исключения). Фактически вызов модуля и сравнение результата с эталоном, ничего более. Могут вкрасться опечатки, конечно. Но от них и спецификации не застрахованы.

Наконец, важный вопрос сочетания тестов и архитектуры решения.

Речь в статье исключительно о модульных тестах (сиречь тестах отдельных модулей в условиях изоляции от других). Они принципиально не пригодны для тестирования архитектуры. Гораздо уместнее для этого применить, скажем, интеграционные или функциональные тесты. Но о них речь впереди, если дойдет дело.

Какие-то тесты не зависят от архитектуры (и с их помощью можно оценить адекватность архитектуры требованиям), какие-то тесты прямо зависят от архитектуры (хотя бы на уровне форматов данных и порядка событий).

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

По поводу прототипирования - зачастую это работа на выброс (и к тому же в другой среде разработки), поэтому нет необходимости применять РУТ к прототипам - качество здесь просто не нужно. А если, как часто бывает, прототип касается пользовательского интерфейса, применение РУТ здесь и вовсе неуместно.

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

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #5 : 28-07-2011 12:46 » 

Цитата: Dale
Предложите практически приемлемую методику оценки устойчивости информационных структур к изменениям, тогда рекомендация действительно приобретет ценность.
Справедливо. Однако и без количественной оценки можно сказать, что стратегия "не делать того, что прямо сейчас не нужно" результативна.

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

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

Цитата: Dale
Неоднократно акцентируется внимание на том, что тест обязан быть элементарным (четыре простейших фазы) и по возможности иметь линейную логику (к сожалению, в Unity это не всегда возможно, если задействованы исключения).
Цитата: Dale
Речь в статье исключительно о модульных тестах (сиречь тестах отдельных модулей в условиях изоляции от других).
Пусть даже без исключений, пусть даже хорошо инкапсулированные модули. Любую ли проверку чего угодно можно описать линейно и элементарно?

А если требованием к системе является поддержка работы по какому-нибудь протоколу с вариативными частями? Нужно будет столько линейных сценариев, сколько ветвей в дереве исполнения плюс их взаимные комбинации? А если модуль имеет "развитой" программный интерфейс, как проверить отсутствие нежелательных взаимных влияний операций этого интерфейса друг на друга (thread-safe, косвенные рекурсии и т.п.)?

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

Цитата: Dale
Давайте и мы последуем мудрому правилу двигаться небольшими итерациями, а то каждый пост получается больше самой статьи и сразу обо всем на свете.
Я так и делаю. Выходит статья - я пишу к ней разные заметки по смежным темам, завязываю дискуссии в более широком контексте, которые могут послужить почвой для других статей. Я специально дожидался, когда статья из "Редакций" перешла в "Архив" - т.е. стала законченной.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #6 : 28-07-2011 13:46 » 

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

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

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

Об этом упоминалось в статье. Можно, но нежелательно. Все тесты провалены разом, неясно, за что хвататься.

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

Чаще поступают именно так. Практики говорят о себе "пишем немного тестов, потом немного кода".

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

Было в статье:

Цитата
Некоторые предпочитают написать все тесты сразу, а потом добавлять понемногу код, стремясь к тому, чтобы на каждом шаге количество проваленных тестов уменьшалось хотя бы на единицу. Другие пишут за раз один-два теста, потом код, который их проходит. Третьи выбирают компромиссное решение: сразу делают пустые заготовки для всех планируемых тестов, чтобы ничего не забыть, а потом реализуют их по одному.
Первый подход мне не нравится тем, что мы сразу же тонем в множестве проваленных тестов, и поначалу трудно решить, за что хвататься в первую очередь. Третий подход привлекателен для людей, не привыкших полагаться на память, поскольку тесты-пустышки образуют своеобразный план работ. Для небольших задач с простыми спецификациями, как в нашем случае, можно ограничиться вторым вариантом. Его мы и выберем.

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

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

А если требованием к системе является поддержка работы по какому-нибудь протоколу с вариативными частями? Нужно будет столько линейных сценариев, сколько ветвей в дереве исполнения плюс их взаимные комбинации? А если модуль имеет "развитой" программный интерфейс, как проверить отсутствие нежелательных взаимных влияний операций этого интерфейса друг на друга (thread-safe, косвенные рекурсии и т.п.)?

Такие высокоуровневые операции следует проверять функциональными тестами. Модульные - это простые тесты элементарных кирпичиков типа "вызвал метод - оценил результат", сложные сценарии им не по зубам.
Записан

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

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Страниц: [1]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines